mirror of
https://github.com/discourse/discourse.git
synced 2025-05-25 19:29:34 +08:00
DEV: implements <Chat::Navbar /> (#24917)
This new navbar component is used for every navbar in chat, full page or drawer, and any screen. This commit also uses this opportunity to correctly decouple drawer-routes from full page routes. This will avoid having this kind of properties in components: `@includeHeader={{false}}`. The header is now defined in the parent template using a navbar. Each route has now its own template wrapped in a div of the name of the route, eg: `<div class="c-routes-threads">..</div>`. The navbar API: ```gjs <Navbar as |navbar|> <navbar.BackButton /> <navbar.Title @title="Foo" /> <navbar.ChannelTitle @channel={{@channel}} /> <navbar.Actions as |action|> <action.CloseThreadButton /> </navbar.Actions> </navbar> ``` The full list of components is listed in `plugins/chat/assets/javascripts/discourse/components/navbar/index.gjs` and `plugins/chat/assets/javascripts/discourse/components/navbar/actions.gjs`. Visually the header is not changing much, only in drawer mode the background has been removed. This commit also introduces a `<List />` component to facilitate rendering lists in chat plugin.
This commit is contained in:
@ -412,11 +412,6 @@ html {
|
|||||||
.reviewable .status span.approved {
|
.reviewable .status span.approved {
|
||||||
color: var(--success-hover);
|
color: var(--success-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chat
|
|
||||||
.chat-channel .open-drawer-btn {
|
|
||||||
color: var(--primary-medium);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// chat
|
// chat
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
<div class="chat-browse-view__header chat-full-page-header">
|
|
||||||
{{#if this.site.mobileView}}
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.index"
|
|
||||||
class="chat-full-page-header__back-btn no-text btn-flat btn"
|
|
||||||
title={{i18n "chat.browse.back"}}
|
|
||||||
>
|
|
||||||
{{d-icon "chevron-left"}}
|
|
||||||
</LinkTo>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<span class="chat-browse-view__title">{{i18n "chat.browse.title"}}</span>
|
|
||||||
|
|
||||||
{{#if this.currentUser.staff}}
|
|
||||||
<DButton
|
|
||||||
@action={{this.createChannel}}
|
|
||||||
@icon="plus"
|
|
||||||
@label={{if this.site.desktopView "chat.create_channel.title"}}
|
|
||||||
class={{concat-class
|
|
||||||
"new-channel-btn"
|
|
||||||
(if this.site.mobileView "btn-flat")
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="chat-browse-view">
|
|
||||||
<div class="chat-browse-view__actions">
|
|
||||||
<nav>
|
|
||||||
<ul class="nav-pills chat-browse-view__filters">
|
|
||||||
{{#each this.tabs as |tab|}}
|
|
||||||
<li class={{concat "chat-browse-view__filter -" tab}}>
|
|
||||||
<LinkTo
|
|
||||||
@route={{concat "chat.browse." tab}}
|
|
||||||
class={{concat "chat-browse-view__filter-link -" tab}}
|
|
||||||
>
|
|
||||||
{{i18n (concat "chat.browse.filter_" tab)}}
|
|
||||||
</LinkTo>
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<DcFilterInput
|
|
||||||
{{did-insert (action this.focusFilterInput)}}
|
|
||||||
@filterAction={{this.debouncedFiltering}}
|
|
||||||
@icons={{hash right="search"}}
|
|
||||||
@containerClass="filter-input"
|
|
||||||
placeholder={{i18n "chat.browse.filter_input_placeholder"}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if
|
|
||||||
(and
|
|
||||||
this.channelsCollection.fetchedOnce (not this.channelsCollection.length)
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
<div class="empty-state">
|
|
||||||
<span class="empty-state-title">{{i18n "chat.empty_state.title"}}</span>
|
|
||||||
<div class="empty-state-body">
|
|
||||||
<p>{{i18n "chat.empty_state.direct_message"}}</p>
|
|
||||||
<DButton
|
|
||||||
@action={{this.showChatNewMessageModal}}
|
|
||||||
@label="chat.empty_state.direct_message_cta"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{else if this.channelsCollection.length}}
|
|
||||||
<LoadMore
|
|
||||||
@selector=".chat-channel-card"
|
|
||||||
@action={{this.channelsCollection.load}}
|
|
||||||
>
|
|
||||||
<div class="chat-browse-view__content_wrapper">
|
|
||||||
<div class="chat-browse-view__content">
|
|
||||||
<div class="chat-browse-view__cards">
|
|
||||||
{{#each this.channelsCollection as |channel|}}
|
|
||||||
<ChatChannelCard @channel={{channel}} />
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ConditionalLoadingSpinner
|
|
||||||
@condition={{this.channelsCollection.loading}}
|
|
||||||
/>
|
|
||||||
</LoadMore>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
@ -1,76 +0,0 @@
|
|||||||
import Component from "@ember/component";
|
|
||||||
import { action, computed } from "@ember/object";
|
|
||||||
import { schedule } from "@ember/runloop";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
|
||||||
import ChatModalCreateChannel from "discourse/plugins/chat/discourse/components/chat/modal/create-channel";
|
|
||||||
import ChatModalNewMessage from "discourse/plugins/chat/discourse/components/chat/modal/new-message";
|
|
||||||
|
|
||||||
const TABS = ["all", "open", "closed", "archived"];
|
|
||||||
|
|
||||||
export default class ChatBrowseView extends Component {
|
|
||||||
@service chatApi;
|
|
||||||
@service modal;
|
|
||||||
|
|
||||||
tagName = "";
|
|
||||||
|
|
||||||
didReceiveAttrs() {
|
|
||||||
super.didReceiveAttrs(...arguments);
|
|
||||||
|
|
||||||
if (!this.channelsCollection) {
|
|
||||||
this.set("channelsCollection", this.chatApi.channels());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.channelsCollection.load({
|
|
||||||
filter: this.filter,
|
|
||||||
status: this.status,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@computed("siteSettings.chat_allow_archiving_channels")
|
|
||||||
get tabs() {
|
|
||||||
if (this.siteSettings.chat_allow_archiving_channels) {
|
|
||||||
return TABS;
|
|
||||||
} else {
|
|
||||||
return [...TABS].removeObject("archived");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
showChatNewMessageModal() {
|
|
||||||
this.modal.show(ChatModalNewMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
onScroll() {
|
|
||||||
discourseDebounce(
|
|
||||||
this,
|
|
||||||
this.channelsCollection.load,
|
|
||||||
{ filter: this.filter, status: this.status },
|
|
||||||
INPUT_DELAY
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
debouncedFiltering(event) {
|
|
||||||
this.set("channelsCollection", this.chatApi.channels());
|
|
||||||
|
|
||||||
discourseDebounce(
|
|
||||||
this,
|
|
||||||
this.channelsCollection.load,
|
|
||||||
{ filter: event.target.value, status: this.status },
|
|
||||||
INPUT_DELAY
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
createChannel() {
|
|
||||||
this.modal.show(ChatModalCreateChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
focusFilterInput(input) {
|
|
||||||
schedule("afterRender", () => input?.focus());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,110 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { LinkTo } from "@ember/routing";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import DButton from "discourse/components/d-button";
|
|
||||||
import icon from "discourse-common/helpers/d-icon";
|
|
||||||
import I18n from "discourse-i18n";
|
|
||||||
import ChannelTitle from "discourse/plugins/chat/discourse/components/channel-title";
|
|
||||||
import ChatModalEditChannelName from "discourse/plugins/chat/discourse/components/chat/modal/edit-channel-name";
|
|
||||||
import ChatChannelStatus from "discourse/plugins/chat/discourse/components/chat-channel-status";
|
|
||||||
|
|
||||||
export default class ChatChannelMessageEmojiPicker extends Component {
|
|
||||||
@service chatChannelInfoRouteOriginManager;
|
|
||||||
@service site;
|
|
||||||
@service modal;
|
|
||||||
@service chatGuardian;
|
|
||||||
|
|
||||||
membersLabel = I18n.t("chat.channel_info.tabs.members");
|
|
||||||
settingsLabel = I18n.t("chat.channel_info.tabs.settings");
|
|
||||||
backToChannelLabel = I18n.t("chat.channel_info.back_to_all_channel");
|
|
||||||
backToAllChannelsLabel = I18n.t("chat.channel_info.back_to_channel");
|
|
||||||
|
|
||||||
get showTabs() {
|
|
||||||
return this.site.desktopView && this.args.channel.isOpen;
|
|
||||||
}
|
|
||||||
|
|
||||||
get canEditChannel() {
|
|
||||||
return (
|
|
||||||
this.chatGuardian.canEditChatChannel() &&
|
|
||||||
(this.args.channel.isCategoryChannel ||
|
|
||||||
(this.args.channel.isDirectMessageChannel &&
|
|
||||||
this.args.channel.chatable.group))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
editChannelTitle() {
|
|
||||||
return this.modal.show(ChatModalEditChannelName, {
|
|
||||||
model: this.args.channel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="chat-full-page-header">
|
|
||||||
<div class="chat-channel-header-details">
|
|
||||||
<div class="chat-full-page-header__left-actions">
|
|
||||||
{{#if this.chatChannelInfoRouteOriginManager.isBrowse}}
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.browse"
|
|
||||||
class="chat-full-page-header__back-btn no-text btn-flat btn"
|
|
||||||
title={{this.backToAllChannelsLabel}}
|
|
||||||
>
|
|
||||||
{{icon "chevron-left"}}
|
|
||||||
</LinkTo>
|
|
||||||
{{else}}
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.channel"
|
|
||||||
@models={{@channel.routeModels}}
|
|
||||||
class="chat-full-page-header__back-btn no-text btn-flat btn"
|
|
||||||
title={{this.backToChannelLabel}}
|
|
||||||
>
|
|
||||||
{{icon "chevron-left"}}
|
|
||||||
</LinkTo>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ChannelTitle @channel={{@channel}} />
|
|
||||||
|
|
||||||
{{#if this.canEditChannel}}
|
|
||||||
<DButton
|
|
||||||
@icon="pencil-alt"
|
|
||||||
class="btn-flat"
|
|
||||||
@action={{this.editChannelTitle}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ChatChannelStatus @channel={{@channel}} />
|
|
||||||
|
|
||||||
<div class="chat-channel-info">
|
|
||||||
{{#if this.showTabs}}
|
|
||||||
<nav class="chat-channel-info__nav">
|
|
||||||
<ul class="nav nav-pills">
|
|
||||||
<li>
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.channel.info.settings"
|
|
||||||
@model={{@channel}}
|
|
||||||
@replace={{true}}
|
|
||||||
>
|
|
||||||
{{this.settingsLabel}}
|
|
||||||
</LinkTo>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.channel.info.members"
|
|
||||||
@model={{@channel}}
|
|
||||||
@replace={{true}}
|
|
||||||
>
|
|
||||||
{{this.membersLabel}}
|
|
||||||
</LinkTo>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{outlet}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -21,6 +21,7 @@ import discourseDebounce from "discourse-common/lib/debounce";
|
|||||||
import { bind } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import and from "truth-helpers/helpers/and";
|
import and from "truth-helpers/helpers/and";
|
||||||
import not from "truth-helpers/helpers/not";
|
import not from "truth-helpers/helpers/not";
|
||||||
|
import ChatChannelStatus from "discourse/plugins/chat/discourse/components/chat-channel-status";
|
||||||
import ChatChannelSubscriptionManager from "discourse/plugins/chat/discourse/lib/chat-channel-subscription-manager";
|
import ChatChannelSubscriptionManager from "discourse/plugins/chat/discourse/lib/chat-channel-subscription-manager";
|
||||||
import {
|
import {
|
||||||
FUTURE,
|
FUTURE,
|
||||||
@ -45,7 +46,6 @@ import ChatComposerChannel from "./chat/composer/channel";
|
|||||||
import ChatScrollToBottomArrow from "./chat/scroll-to-bottom-arrow";
|
import ChatScrollToBottomArrow from "./chat/scroll-to-bottom-arrow";
|
||||||
import ChatSelectionManager from "./chat/selection-manager";
|
import ChatSelectionManager from "./chat/selection-manager";
|
||||||
import ChatChannelPreviewCard from "./chat-channel-preview-card";
|
import ChatChannelPreviewCard from "./chat-channel-preview-card";
|
||||||
import ChatFullPageHeader from "./chat-full-page-header";
|
|
||||||
import ChatMentionWarnings from "./chat-mention-warnings";
|
import ChatMentionWarnings from "./chat-mention-warnings";
|
||||||
import Message from "./chat-message";
|
import Message from "./chat-message";
|
||||||
import ChatNotices from "./chat-notices";
|
import ChatNotices from "./chat-notices";
|
||||||
@ -719,14 +719,9 @@ export default class ChatChannel extends Component {
|
|||||||
{{didUpdate this.loadMessages @targetMessageId}}
|
{{didUpdate this.loadMessages @targetMessageId}}
|
||||||
data-id={{@channel.id}}
|
data-id={{@channel.id}}
|
||||||
>
|
>
|
||||||
<ChatFullPageHeader
|
|
||||||
@channel={{@channel}}
|
|
||||||
@onCloseFullScreen={{this.onCloseFullScreen}}
|
|
||||||
@displayed={{this.includeHeader}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
<ChatChannelStatus @channel={{@channel}} />
|
||||||
<ChatNotices @channel={{@channel}} />
|
<ChatNotices @channel={{@channel}} />
|
||||||
|
|
||||||
<ChatMentionWarnings />
|
<ChatMentionWarnings />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import I18n from "discourse-i18n";
|
|
||||||
import and from "truth-helpers/helpers/and";
|
|
||||||
import ChatDrawerHeader from "discourse/plugins/chat/discourse/components/chat-drawer/header";
|
|
||||||
import ChatDrawerHeaderBackLink from "discourse/plugins/chat/discourse/components/chat-drawer/header/back-link";
|
|
||||||
import ChatDrawerHeaderRightActions from "discourse/plugins/chat/discourse/components/chat-drawer/header/right-actions";
|
|
||||||
import ChatDrawerHeaderTitle from "discourse/plugins/chat/discourse/components/chat-drawer/header/title";
|
|
||||||
import ChatThreadList from "discourse/plugins/chat/discourse/components/chat-thread-list";
|
|
||||||
|
|
||||||
export default class ChatDrawerChannelThreads extends Component {
|
|
||||||
@service appEvents;
|
|
||||||
@service chat;
|
|
||||||
@service chatStateManager;
|
|
||||||
@service chatChannelsManager;
|
|
||||||
|
|
||||||
backLinkTitle = I18n.t("chat.return_to_list");
|
|
||||||
|
|
||||||
@action
|
|
||||||
fetchChannel() {
|
|
||||||
if (!this.args.params?.channelId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.chatChannelsManager
|
|
||||||
.find(this.args.params.channelId)
|
|
||||||
.then((channel) => {
|
|
||||||
this.chat.activeChannel = channel;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<ChatDrawerHeader @toggleExpand={{@drawerActions.toggleExpand}}>
|
|
||||||
{{#if
|
|
||||||
(and this.chatStateManager.isDrawerExpanded this.chat.activeChannel)
|
|
||||||
}}
|
|
||||||
<div class="chat-drawer-header__left-actions">
|
|
||||||
<div class="chat-drawer-header__top-line">
|
|
||||||
<ChatDrawerHeaderBackLink
|
|
||||||
@route="chat.channel"
|
|
||||||
@title={{this.backLinkTitle}}
|
|
||||||
@routeModels={{this.chat.activeChannel.routeModels}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<ChatDrawerHeaderTitle
|
|
||||||
@title="chat.threads.list"
|
|
||||||
@icon="discourse-threads"
|
|
||||||
@channelName={{this.chat.activeChannel.title}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ChatDrawerHeaderRightActions @drawerActions={{@drawerActions}} />
|
|
||||||
</ChatDrawerHeader>
|
|
||||||
|
|
||||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
|
||||||
<div class="chat-drawer-content" {{didInsert this.fetchChannel}}>
|
|
||||||
{{#if this.chat.activeChannel}}
|
|
||||||
<ChatThreadList
|
|
||||||
@channel={{this.chat.activeChannel}}
|
|
||||||
@includeHeader={{false}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { on } from "@ember/modifier";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import i18n from "discourse-common/helpers/i18n";
|
|
||||||
|
|
||||||
export default class ChatDrawerHeader extends Component {
|
|
||||||
@service chatStateManager;
|
|
||||||
|
|
||||||
<template>
|
|
||||||
{{! template-lint-disable no-invalid-interactive }}
|
|
||||||
<div
|
|
||||||
role="region"
|
|
||||||
aria-label={{i18n "chat.aria_roles.header"}}
|
|
||||||
class="chat-drawer-header"
|
|
||||||
{{on "click" @toggleExpand}}
|
|
||||||
title={{if
|
|
||||||
this.chatStateManager.isDrawerExpanded
|
|
||||||
(i18n "chat.collapse")
|
|
||||||
(i18n "chat.expand")
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{{yield}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { array } from "@ember/helper";
|
|
||||||
import { LinkTo } from "@ember/routing";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import dIcon from "discourse-common/helpers/d-icon";
|
|
||||||
import or from "truth-helpers/helpers/or";
|
|
||||||
|
|
||||||
export default class ChatDrawerHeaderBackLink extends Component {
|
|
||||||
@service chatStateManager;
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LinkTo
|
|
||||||
title={{@title}}
|
|
||||||
class="chat-drawer-header__back-btn"
|
|
||||||
@route={{@route}}
|
|
||||||
@models={{or @routeModels (array)}}
|
|
||||||
>
|
|
||||||
{{dIcon "chevron-left"}}
|
|
||||||
</LinkTo>
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { on } from "@ember/modifier";
|
|
||||||
import { LinkTo } from "@ember/routing";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import ChannelTitle from "../../channel-title";
|
|
||||||
|
|
||||||
export default class ChatDrawerChannelHeaderTitle extends Component {
|
|
||||||
@service chatStateManager;
|
|
||||||
|
|
||||||
<template>
|
|
||||||
{{#if @channel}}
|
|
||||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
|
||||||
<LinkTo
|
|
||||||
@route={{if
|
|
||||||
@channel.isDirectMessageChannel
|
|
||||||
"chat.channel.info.settings"
|
|
||||||
"chat.channel.info.members"
|
|
||||||
}}
|
|
||||||
@models={{@channel.routeModels}}
|
|
||||||
class="chat-drawer-header__title"
|
|
||||||
>
|
|
||||||
<div class="chat-drawer-header__top-line">
|
|
||||||
<ChannelTitle @channel={{@channel}} />
|
|
||||||
</div>
|
|
||||||
</LinkTo>
|
|
||||||
{{else}}
|
|
||||||
<div
|
|
||||||
role="button"
|
|
||||||
{{on "click" @drawerActions.toggleExpand}}
|
|
||||||
class="chat-drawer-header__title"
|
|
||||||
>
|
|
||||||
<div class="chat-drawer-header__top-line">
|
|
||||||
<ChannelTitle @channel={{@channel}}>
|
|
||||||
{{#if @channel.tracking.unreadCount}}
|
|
||||||
<span class="chat-unread-count">
|
|
||||||
{{@channel.tracking.unreadCount}}
|
|
||||||
</span>
|
|
||||||
{{/if}}
|
|
||||||
</ChannelTitle>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
import DButton from "discourse/components/d-button";
|
|
||||||
|
|
||||||
const CloseButton = <template>
|
|
||||||
<DButton
|
|
||||||
@icon="times"
|
|
||||||
@action={{@close}}
|
|
||||||
@title="chat.close"
|
|
||||||
class="btn-flat btn-link chat-drawer-header__close-btn"
|
|
||||||
/>
|
|
||||||
</template>;
|
|
||||||
|
|
||||||
export default CloseButton;
|
|
@ -1,18 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import DButton from "discourse/components/d-button";
|
|
||||||
|
|
||||||
export default class ChatDrawerHeaderFullPageButton extends Component {
|
|
||||||
@service chatStateManager;
|
|
||||||
|
|
||||||
<template>
|
|
||||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
|
||||||
<DButton
|
|
||||||
@icon="discourse-expand"
|
|
||||||
class="btn-flat btn-link chat-drawer-header__full-screen-btn"
|
|
||||||
@title="chat.open_full_page"
|
|
||||||
@action={{@openInFullPage}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import i18n from "discourse-common/helpers/i18n";
|
|
||||||
import BackLink from "./back-link";
|
|
||||||
|
|
||||||
export default class ChatDrawerHeaderLeftActions extends Component {
|
|
||||||
@service chatStateManager;
|
|
||||||
|
|
||||||
<template>
|
|
||||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
|
||||||
<div class="chat-drawer-header__left-actions">
|
|
||||||
<div class="chat-drawer-header__top-line">
|
|
||||||
<BackLink @route="chat" @title={{i18n "chat.return_to_list"}} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import ThreadsListButton from "../../chat/thread/threads-list-button";
|
|
||||||
import CloseButton from "./close-button";
|
|
||||||
import FullPageButton from "./full-page-button";
|
|
||||||
import ToggleExpandButton from "./toggle-expand-button";
|
|
||||||
|
|
||||||
export default class ChatDrawerHeaderRightActions extends Component {
|
|
||||||
@service chat;
|
|
||||||
|
|
||||||
get showThreadsListButton() {
|
|
||||||
return this.chat.activeChannel?.threadingEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="chat-drawer-header__right-actions">
|
|
||||||
<div class="chat-drawer-header__top-line">
|
|
||||||
{{#if this.showThreadsListButton}}
|
|
||||||
<ThreadsListButton @channel={{this.chat.activeChannel}} />
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<ToggleExpandButton @toggleExpand={{@drawerActions.toggleExpand}} />
|
|
||||||
|
|
||||||
<FullPageButton @openInFullPage={{@drawerActions.openInFullPage}} />
|
|
||||||
|
|
||||||
<CloseButton @close={{@drawerActions.close}} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
|
||||||
import icon from "discourse-common/helpers/d-icon";
|
|
||||||
import I18n from "discourse-i18n";
|
|
||||||
|
|
||||||
export default class ChatDrawerHeaderTitle extends Component {
|
|
||||||
get headerTitle() {
|
|
||||||
if (this.args.title) {
|
|
||||||
return I18n.t(this.args.title);
|
|
||||||
}
|
|
||||||
return replaceEmoji(this.args.translatedTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
get showChannel() {
|
|
||||||
return this.args.channelName ?? false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get showIcon() {
|
|
||||||
return this.args.icon ?? false;
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<span class="chat-drawer-header__title">
|
|
||||||
<div class="chat-drawer-header__top-line">
|
|
||||||
<span class="chat-drawer-header__icon">
|
|
||||||
{{#if this.showIcon}}
|
|
||||||
{{icon @icon}}
|
|
||||||
{{/if}}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="chat-drawer-header__title-text">{{this.headerTitle}}</span>
|
|
||||||
|
|
||||||
{{#if this.showChannel}}
|
|
||||||
<span class="chat-drawer-header__divider">-</span>
|
|
||||||
<span class="chat-drawer-header__channel-name">{{@channelName}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import i18n from "discourse-common/helpers/i18n";
|
|
||||||
import ChannelsList from "../channels-list";
|
|
||||||
import Header from "./header";
|
|
||||||
import RightActions from "./header/right-actions";
|
|
||||||
|
|
||||||
export default class ChatDrawerIndex extends Component {
|
|
||||||
@service chatStateManager;
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Header @toggleExpand={{@drawerActions.toggleExpand}}>
|
|
||||||
<div class="chat-drawer-header__title">
|
|
||||||
<div class="chat-drawer-header__top-line">
|
|
||||||
{{i18n "chat.heading"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<RightActions @drawerActions={{@drawerActions}} />
|
|
||||||
</Header>
|
|
||||||
|
|
||||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
|
||||||
<div class="chat-drawer-content">
|
|
||||||
<ChannelsList />
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import I18n from "discourse-i18n";
|
|
||||||
import ChatDrawerHeader from "discourse/plugins/chat/discourse/components/chat-drawer/header";
|
|
||||||
import ChatDrawerHeaderBackLink from "discourse/plugins/chat/discourse/components/chat-drawer/header/back-link";
|
|
||||||
import ChatDrawerHeaderRightActions from "discourse/plugins/chat/discourse/components/chat-drawer/header/right-actions";
|
|
||||||
import ChatDrawerHeaderTitle from "discourse/plugins/chat/discourse/components/chat-drawer/header/title";
|
|
||||||
import UserThreads from "discourse/plugins/chat/discourse/components/user-threads";
|
|
||||||
|
|
||||||
export default class ChatDrawerThreads extends Component {
|
|
||||||
@service appEvents;
|
|
||||||
@service chat;
|
|
||||||
@service chatStateManager;
|
|
||||||
@service chatChannelsManager;
|
|
||||||
|
|
||||||
backLinkTitle = I18n.t("chat.return_to_list");
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<ChatDrawerHeader @toggleExpand={{@drawerActions.toggleExpand}}>
|
|
||||||
|
|
||||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
|
||||||
<div class="chat-drawer-header__left-actions">
|
|
||||||
<div class="chat-drawer-header__top-line">
|
|
||||||
<ChatDrawerHeaderBackLink
|
|
||||||
@route="chat"
|
|
||||||
@title={{this.backLink.title}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<ChatDrawerHeaderTitle
|
|
||||||
@title="chat.threads.list"
|
|
||||||
@icon="discourse-threads"
|
|
||||||
@channelName={{this.chat.activeChannel.title}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ChatDrawerHeaderRightActions @drawerActions={{@drawerActions}} />
|
|
||||||
</ChatDrawerHeader>
|
|
||||||
|
|
||||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
|
||||||
<div class="chat-drawer-content">
|
|
||||||
<UserThreads />
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { on } from "@ember/modifier";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { LinkTo } from "@ember/routing";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import DButton from "discourse/components/d-button";
|
|
||||||
import concatClass from "discourse/helpers/concat-class";
|
|
||||||
import icon from "discourse-common/helpers/d-icon";
|
|
||||||
import and from "truth-helpers/helpers/and";
|
|
||||||
import or from "truth-helpers/helpers/or";
|
|
||||||
import ChannelTitle from "discourse/plugins/chat/discourse/components/channel-title";
|
|
||||||
import ChatModalEditChannelName from "discourse/plugins/chat/discourse/components/chat/modal/edit-channel-name";
|
|
||||||
import ThreadsListButton from "discourse/plugins/chat/discourse/components/chat/thread/threads-list-button";
|
|
||||||
import ChatChannelStatus from "discourse/plugins/chat/discourse/components/chat-channel-status";
|
|
||||||
|
|
||||||
export default class ChatFullPageHeader extends Component {
|
|
||||||
@service chatStateManager;
|
|
||||||
@service modal;
|
|
||||||
@service router;
|
|
||||||
@service site;
|
|
||||||
|
|
||||||
get displayed() {
|
|
||||||
return this.args.displayed ?? true;
|
|
||||||
}
|
|
||||||
|
|
||||||
get showThreadsListButton() {
|
|
||||||
return (
|
|
||||||
this.args.channel.threadingEnabled &&
|
|
||||||
this.router.currentRoute.name !== "chat.channel.threads" &&
|
|
||||||
this.router.currentRoute.name !== "chat.channel.thread.index" &&
|
|
||||||
this.router.currentRoute.name !== "chat.channel.thread"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
editChannelTitle() {
|
|
||||||
return this.modal.show(ChatModalEditChannelName, {
|
|
||||||
model: this.args.channel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
trapMouse(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
{{! template-lint-disable no-invalid-interactive }}
|
|
||||||
{{#if (and this.chatStateManager.isFullPageActive this.displayed)}}
|
|
||||||
<div
|
|
||||||
class={{concatClass
|
|
||||||
"chat-full-page-header"
|
|
||||||
(unless @channel.isFollowing "-not-following")
|
|
||||||
}}
|
|
||||||
{{on "mousemove" this.trapMouse}}
|
|
||||||
>
|
|
||||||
<div class="chat-channel-header-details">
|
|
||||||
{{#if this.site.mobileView}}
|
|
||||||
<div class="chat-full-page-header__left-actions">
|
|
||||||
<LinkTo
|
|
||||||
@route="chat"
|
|
||||||
class="chat-full-page-header__back-btn no-text btn-flat"
|
|
||||||
>
|
|
||||||
{{icon "chevron-left"}}
|
|
||||||
</LinkTo>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.channel.info"
|
|
||||||
@models={{@channel.routeModels}}
|
|
||||||
class="chat-channel-title-wrapper"
|
|
||||||
>
|
|
||||||
<ChannelTitle @channel={{@channel}} />
|
|
||||||
</LinkTo>
|
|
||||||
|
|
||||||
{{#if (or @channel.threadingEnabled this.site.desktopView)}}
|
|
||||||
<div class="chat-full-page-header__right-actions">
|
|
||||||
{{#if this.site.desktopView}}
|
|
||||||
<DButton
|
|
||||||
@icon="discourse-compress"
|
|
||||||
@title="chat.close_full_page"
|
|
||||||
class="open-drawer-btn btn-flat"
|
|
||||||
@action={{@onCloseFullScreen}}
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.showThreadsListButton}}
|
|
||||||
<ThreadsListButton @channel={{@channel}} />
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ChatChannelStatus @channel={{@channel}} />
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -98,12 +98,15 @@ export default class ChatMessageThreadIndicator extends Component {
|
|||||||
|
|
||||||
@bind
|
@bind
|
||||||
openThread(event) {
|
openThread(event) {
|
||||||
if (event.type === "keydown" && event.key !== "Enter") {
|
if (event?.type === "keydown" && event?.key !== "Enter") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle middle mouse
|
// handle middle mouse
|
||||||
if (event.type === "mousedown" && (event.which === 2 || event.shiftKey)) {
|
if (
|
||||||
|
event?.type === "mousedown" &&
|
||||||
|
(event?.which === 2 || event?.shiftKey)
|
||||||
|
) {
|
||||||
window.open(
|
window.open(
|
||||||
getURL(
|
getURL(
|
||||||
this.router.urlFor(
|
this.router.urlFor(
|
||||||
|
@ -41,7 +41,7 @@ export default class ChatRetentionReminder extends Component {
|
|||||||
<DButton
|
<DButton
|
||||||
@action={{this.dismiss}}
|
@action={{this.dismiss}}
|
||||||
@icon="times"
|
@icon="times"
|
||||||
class="btn-flat dismiss-btn"
|
class="btn no-text btn-icon btn-flat no-text dismiss-btn"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -7,7 +7,6 @@ import isElementInViewport from "discourse/lib/is-element-in-viewport";
|
|||||||
import { bind } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
import eq from "truth-helpers/helpers/eq";
|
import eq from "truth-helpers/helpers/eq";
|
||||||
import ChatThreadListHeader from "discourse/plugins/chat/discourse/components/chat/thread-list/header";
|
|
||||||
import ChatThreadListItem from "discourse/plugins/chat/discourse/components/chat/thread-list/item";
|
import ChatThreadListItem from "discourse/plugins/chat/discourse/components/chat/thread-list/item";
|
||||||
import ChatTrackMessage from "discourse/plugins/chat/discourse/modifiers/chat/track-message";
|
import ChatTrackMessage from "discourse/plugins/chat/discourse/modifiers/chat/track-message";
|
||||||
|
|
||||||
@ -179,10 +178,6 @@ export default class ChatThreadList extends Component {
|
|||||||
<template>
|
<template>
|
||||||
{{#if this.shouldRender}}
|
{{#if this.shouldRender}}
|
||||||
<div class="chat-thread-list" {{this.subscribe @channel}}>
|
<div class="chat-thread-list" {{this.subscribe @channel}}>
|
||||||
{{#if @includeHeader}}
|
|
||||||
<ChatThreadListHeader @channel={{@channel}} />
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="chat-thread-list__items" {{this.fill}}>
|
<div class="chat-thread-list__items" {{this.fill}}>
|
||||||
|
|
||||||
{{#each this.sortedThreads key="id" as |thread|}}
|
{{#each this.sortedThreads key="id" as |thread|}}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
import NotificationsButtonComponent from "select-kit/components/notifications-button";
|
||||||
|
import { threadNotificationButtonLevels } from "discourse/plugins/chat/discourse/lib/chat-notification-levels";
|
||||||
|
|
||||||
|
export default NotificationsButtonComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["thread-notifications-button"],
|
||||||
|
classNames: ["thread-notifications-button"],
|
||||||
|
content: threadNotificationButtonLevels,
|
||||||
|
|
||||||
|
selectKitOptions: {
|
||||||
|
i18nPrefix: "chat.thread.notifications",
|
||||||
|
showFullTitle: false,
|
||||||
|
btnCustomClasses: "btn-flat",
|
||||||
|
},
|
||||||
|
});
|
@ -36,7 +36,6 @@ import ChatScrollableList from "../modifiers/chat/scrollable-list";
|
|||||||
import ChatComposerThread from "./chat/composer/thread";
|
import ChatComposerThread from "./chat/composer/thread";
|
||||||
import ChatScrollToBottomArrow from "./chat/scroll-to-bottom-arrow";
|
import ChatScrollToBottomArrow from "./chat/scroll-to-bottom-arrow";
|
||||||
import ChatSelectionManager from "./chat/selection-manager";
|
import ChatSelectionManager from "./chat/selection-manager";
|
||||||
import ChatThreadHeader from "./chat/thread/header";
|
|
||||||
import Message from "./chat-message";
|
import Message from "./chat-message";
|
||||||
import ChatSkeleton from "./chat-skeleton";
|
import ChatSkeleton from "./chat-skeleton";
|
||||||
import ChatUploadDropZone from "./chat-upload-drop-zone";
|
import ChatUploadDropZone from "./chat-upload-drop-zone";
|
||||||
@ -493,10 +492,6 @@ export default class ChatThread extends Component {
|
|||||||
{{didInsert this.setup}}
|
{{didInsert this.setup}}
|
||||||
{{willDestroy this.teardown}}
|
{{willDestroy this.teardown}}
|
||||||
>
|
>
|
||||||
{{#if @includeHeader}}
|
|
||||||
<ChatThreadHeader @channel={{@thread.channel}} @thread={{@thread}} />
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="chat-thread__body popper-viewport chat-messages-scroll"
|
class="chat-thread__body popper-viewport chat-messages-scroll"
|
||||||
{{didInsert this.setScrollable}}
|
{{didInsert this.setScrollable}}
|
||||||
|
@ -4,24 +4,20 @@ import { action } from "@ember/object";
|
|||||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
|
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
import and from "truth-helpers/helpers/and";
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
import ChatDrawerHeader from "discourse/plugins/chat/discourse/components/chat-drawer/header";
|
|
||||||
import ChatDrawerHeaderBackLink from "discourse/plugins/chat/discourse/components/chat-drawer/header/back-link";
|
|
||||||
import ChatDrawerHeaderRightActions from "discourse/plugins/chat/discourse/components/chat-drawer/header/right-actions";
|
|
||||||
import ChatDrawerHeaderTitle from "discourse/plugins/chat/discourse/components/chat-drawer/header/title";
|
|
||||||
import ChatThread from "discourse/plugins/chat/discourse/components/chat-thread";
|
import ChatThread from "discourse/plugins/chat/discourse/components/chat-thread";
|
||||||
|
|
||||||
export default class ChatDrawerThread extends Component {
|
export default class ChatDrawerRoutesChannelThread extends Component {
|
||||||
@service appEvents;
|
|
||||||
@service chat;
|
@service chat;
|
||||||
@service chatStateManager;
|
@service chatStateManager;
|
||||||
@service chatChannelsManager;
|
@service chatChannelsManager;
|
||||||
@service chatHistory;
|
@service chatHistory;
|
||||||
|
|
||||||
get backLink() {
|
get backButton() {
|
||||||
const link = {
|
const link = {
|
||||||
models: this.chat.activeChannel.routeModels,
|
models: this.chat.activeChannel?.routeModels,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.chatHistory.previousRoute?.name === "chat.channel.threads") {
|
if (this.chatHistory.previousRoute?.name === "chat.channel.threads") {
|
||||||
@ -47,14 +43,16 @@ export default class ChatDrawerThread extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
fetchChannelAndThread() {
|
async fetchChannelAndThread() {
|
||||||
if (!this.args.params?.channelId || !this.args.params?.threadId) {
|
if (!this.args.params?.channelId || !this.args.params?.threadId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.chatChannelsManager
|
try {
|
||||||
.find(this.args.params.channelId)
|
const channel = await this.chatChannelsManager.find(
|
||||||
.then((channel) => {
|
this.args.params.channelId
|
||||||
|
);
|
||||||
|
|
||||||
this.chat.activeChannel = channel;
|
this.chat.activeChannel = channel;
|
||||||
|
|
||||||
channel.threadsManager
|
channel.threadsManager
|
||||||
@ -62,29 +60,25 @@ export default class ChatDrawerThread extends Component {
|
|||||||
.then((thread) => {
|
.then((thread) => {
|
||||||
this.chat.activeChannel.activeThread = thread;
|
this.chat.activeChannel.activeThread = thread;
|
||||||
});
|
});
|
||||||
});
|
} catch (error) {
|
||||||
|
popupAjaxError(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ChatDrawerHeader @toggleExpand={{@drawerActions.toggleExpand}}>
|
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
|
||||||
{{#if
|
<navbar.BackButton
|
||||||
(and this.chatStateManager.isDrawerExpanded this.chat.activeChannel)
|
@title={{this.backButton.title}}
|
||||||
}}
|
@route={{this.backButton.route}}
|
||||||
<div class="chat-drawer-header__left-actions">
|
@routeModels={{this.backButton.models}}
|
||||||
<div class="chat-drawer-header__top-line">
|
|
||||||
<ChatDrawerHeaderBackLink
|
|
||||||
@route={{this.backLink.route}}
|
|
||||||
@title={{this.backLink.title}}
|
|
||||||
@routeModels={{this.backLink.models}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
<navbar.Title @title={{this.threadTitle}} @icon="discourse-threads" />
|
||||||
</div>
|
<navbar.Actions as |action|>
|
||||||
{{/if}}
|
<action.ToggleDrawerButton />
|
||||||
|
<action.FullPageButton />
|
||||||
<ChatDrawerHeaderTitle @translatedTitle={{this.threadTitle}} />
|
<action.CloseDrawerButton />
|
||||||
|
</navbar.Actions>
|
||||||
<ChatDrawerHeaderRightActions @drawerActions={{@drawerActions}} />
|
</Navbar>
|
||||||
</ChatDrawerHeader>
|
|
||||||
|
|
||||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||||
<div
|
<div
|
@ -0,0 +1,68 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import htmlSafe from "discourse-common/helpers/html-safe";
|
||||||
|
import I18n from "discourse-i18n";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
import ChatThreadList from "discourse/plugins/chat/discourse/components/chat-thread-list";
|
||||||
|
|
||||||
|
export default class ChatDrawerRoutesChannelThreads extends Component {
|
||||||
|
@service chat;
|
||||||
|
@service chatChannelsManager;
|
||||||
|
|
||||||
|
backLinkTitle = I18n.t("chat.return_to_list");
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return htmlSafe(
|
||||||
|
I18n.t("chat.threads.list") +
|
||||||
|
" - " +
|
||||||
|
replaceEmoji(this.chat.activeChannel.title)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async fetchChannel() {
|
||||||
|
if (!this.args.params?.channelId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const channel = await this.chatChannelsManager.find(
|
||||||
|
this.args.params.channelId
|
||||||
|
);
|
||||||
|
this.chat.activeChannel = channel;
|
||||||
|
} catch (error) {
|
||||||
|
popupAjaxError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.chat.activeChannel}}
|
||||||
|
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
|
||||||
|
<navbar.BackButton
|
||||||
|
@title={{this.backLinkTitle}}
|
||||||
|
@route="chat.channel"
|
||||||
|
@routeModels={{this.chat.activeChannel?.routeModels}}
|
||||||
|
/>
|
||||||
|
<navbar.Title @title={{this.title}} @icon="discourse-threads" />
|
||||||
|
<navbar.Actions as |action|>
|
||||||
|
<action.ToggleDrawerButton />
|
||||||
|
<action.FullPageButton />
|
||||||
|
<action.CloseDrawerButton />
|
||||||
|
</navbar.Actions>
|
||||||
|
</Navbar>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="chat-drawer-content" {{didInsert this.fetchChannel}}>
|
||||||
|
{{#if this.chat.activeChannel}}
|
||||||
|
<ChatThreadList
|
||||||
|
@channel={{this.chat.activeChannel}}
|
||||||
|
@includeHeader={{false}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -4,14 +4,10 @@ import { action } from "@ember/object";
|
|||||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
|
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import ChatChannel from "../chat-channel";
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
import Header from "./header";
|
import ChatChannel from "discourse/plugins/chat/discourse/components/chat-channel";
|
||||||
import ChannelTitle from "./header/channel-title";
|
|
||||||
import LeftActions from "./header/left-actions";
|
|
||||||
import RightActions from "./header/right-actions";
|
|
||||||
|
|
||||||
export default class ChatDrawerChannel extends Component {
|
export default class ChatDrawerRoutesChannel extends Component {
|
||||||
@service appEvents;
|
|
||||||
@service chat;
|
@service chat;
|
||||||
@service chatStateManager;
|
@service chatStateManager;
|
||||||
@service chatChannelsManager;
|
@service chatChannelsManager;
|
||||||
@ -30,16 +26,16 @@ export default class ChatDrawerChannel extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Header @toggleExpand={{@drawerActions.toggleExpand}}>
|
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
|
||||||
<LeftActions />
|
<navbar.BackButton />
|
||||||
|
<navbar.ChannelTitle @channel={{this.chat.activeChannel}} />
|
||||||
<ChannelTitle
|
<navbar.Actions as |action|>
|
||||||
@channel={{this.chat.activeChannel}}
|
<action.ThreadsListButton @channel={{this.chat.activeChannel}} />
|
||||||
@drawerActions={{@drawerActions}}
|
<action.ToggleDrawerButton />
|
||||||
/>
|
<action.FullPageButton />
|
||||||
|
<action.CloseDrawerButton />
|
||||||
<RightActions @drawerActions={{@drawerActions}} />
|
</navbar.Actions>
|
||||||
</Header>
|
</Navbar>
|
||||||
|
|
||||||
{{#if this.chatStateManager.isDrawerExpanded}}
|
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||||
<div
|
<div
|
@ -0,0 +1,27 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
|
import ChannelsList from "discourse/plugins/chat/discourse/components/channels-list";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
|
||||||
|
export default class ChatDrawerRoutesChannels extends Component {
|
||||||
|
@service chat;
|
||||||
|
@service chatStateManager;
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
|
||||||
|
<navbar.Title @title={{i18n "chat.heading"}} />
|
||||||
|
<navbar.Actions as |action|>
|
||||||
|
<action.ToggleDrawerButton />
|
||||||
|
<action.FullPageButton />
|
||||||
|
<action.CloseDrawerButton />
|
||||||
|
</navbar.Actions>
|
||||||
|
</Navbar>
|
||||||
|
|
||||||
|
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||||
|
<div class="chat-drawer-content">
|
||||||
|
<ChannelsList />
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
|
import I18n from "discourse-i18n";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
import UserThreads from "discourse/plugins/chat/discourse/components/user-threads";
|
||||||
|
|
||||||
|
export default class ChatDrawerRoutesThreads extends Component {
|
||||||
|
@service chat;
|
||||||
|
@service chatStateManager;
|
||||||
|
|
||||||
|
backButtonTitle = I18n.t("chat.return_to_list");
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Navbar @onClick={{this.chat.toggleDrawer}} as |navbar|>
|
||||||
|
<navbar.BackButton @title={{this.backButtonTitle}} />
|
||||||
|
<navbar.Title
|
||||||
|
@title={{i18n "chat.threads.list"}}
|
||||||
|
@icon="discourse-threads"
|
||||||
|
as |title|
|
||||||
|
>
|
||||||
|
<title.SubTitle @title={{this.chat.activeChannel.title}} />
|
||||||
|
</navbar.Title>
|
||||||
|
<navbar.Actions as |action|>
|
||||||
|
<action.ThreadsListButton />
|
||||||
|
<action.ToggleDrawerButton />
|
||||||
|
<action.FullPageButton />
|
||||||
|
<action.CloseDrawerButton />
|
||||||
|
</navbar.Actions>
|
||||||
|
</Navbar>
|
||||||
|
|
||||||
|
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||||
|
<div class="chat-drawer-content">
|
||||||
|
<UserThreads />
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
|
||||||
|
export default class EmptyState extends Component {
|
||||||
|
<template>
|
||||||
|
<div class="c-list-empty-state" ...attributes>
|
||||||
|
{{yield}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { hash } from "@ember/helper";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { modifier } from "ember-modifier";
|
||||||
|
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
||||||
|
import isElementInViewport from "discourse/lib/is-element-in-viewport";
|
||||||
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
|
import EmptyState from "./empty-state";
|
||||||
|
import Item from "./item";
|
||||||
|
|
||||||
|
export default class List extends Component {
|
||||||
|
loadMore = modifier((element) => {
|
||||||
|
this.intersectionObserver = new IntersectionObserver(this.loadCollection);
|
||||||
|
this.intersectionObserver.observe(element);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
this.intersectionObserver.disconnect();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
fill = modifier((element) => {
|
||||||
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
|
if (isElementInViewport(element)) {
|
||||||
|
this.loadCollection();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resizeObserver.observe(element);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
this.resizeObserver.disconnect();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
get itemComponent() {
|
||||||
|
return this.args.itemComponent ?? Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
get emptyStateComponent() {
|
||||||
|
return EmptyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
loadCollection() {
|
||||||
|
discourseDebounce(this, this.debouncedLoadCollection, INPUT_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
async debouncedLoadCollection() {
|
||||||
|
await this.args.collection.load({ limit: 10 });
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-list">
|
||||||
|
<div {{this.fill}} ...attributes>
|
||||||
|
{{#each @collection.items as |item|}}
|
||||||
|
{{yield (hash Item=(component this.itemComponent item=item))}}
|
||||||
|
{{else}}
|
||||||
|
{{#if @collection.fetchedOnce}}
|
||||||
|
{{yield (hash EmptyState=this.emptyStateComponent)}}
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div {{this.loadMore}}>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ConditionalLoadingSpinner @condition={{@collection.loading}} />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
|
||||||
|
export default class Item extends Component {
|
||||||
|
<template>
|
||||||
|
{{yield @item}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { hash } from "@ember/helper";
|
||||||
|
import CloseDrawerButton from "./close-drawer-button";
|
||||||
|
import CloseThreadButton from "./close-thread-button";
|
||||||
|
import CloseThreadsButton from "./close-threads-button";
|
||||||
|
import FullPageButton from "./full-page-button";
|
||||||
|
import NewChannelButton from "./new-channel-button";
|
||||||
|
import OpenDrawerButton from "./open-drawer-button";
|
||||||
|
import ThreadSettingsButton from "./thread-settings-button";
|
||||||
|
import ThreadTrackingDropdown from "./thread-tracking-dropdown";
|
||||||
|
import ThreadsListButton from "./threads-list-button";
|
||||||
|
import ToggleDrawerButton from "./toggle-drawer-button";
|
||||||
|
|
||||||
|
export default class ChatNavbarActions extends Component {
|
||||||
|
get openDrawerButtonComponent() {
|
||||||
|
return OpenDrawerButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get newChannelButtonComponent() {
|
||||||
|
return NewChannelButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get threadTrackingDropdownComponent() {
|
||||||
|
return ThreadTrackingDropdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
get closeThreadButtonComponent() {
|
||||||
|
return CloseThreadButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get closeThreadsButtonComponent() {
|
||||||
|
return CloseThreadsButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get threadSettingsButtonComponent() {
|
||||||
|
return ThreadSettingsButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get threadsListButtonComponent() {
|
||||||
|
return ThreadsListButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get closeDrawerButtonComponent() {
|
||||||
|
return CloseDrawerButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get toggleDrawerButtonComponent() {
|
||||||
|
return ToggleDrawerButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get chatNavbarFullPageButtonComponent() {
|
||||||
|
return FullPageButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<nav class="c-navbar__actions">
|
||||||
|
{{yield
|
||||||
|
(hash
|
||||||
|
OpenDrawerButton=this.openDrawerButtonComponent
|
||||||
|
NewChannelButton=this.newChannelButtonComponent
|
||||||
|
ThreadTrackingDropdown=this.threadTrackingDropdownComponent
|
||||||
|
CloseThreadButton=this.closeThreadButtonComponent
|
||||||
|
CloseThreadsButton=this.closeThreadsButtonComponent
|
||||||
|
ThreadSettingsButton=this.threadSettingsButtonComponent
|
||||||
|
ThreadsListButton=this.threadsListButtonComponent
|
||||||
|
CloseDrawerButton=this.closeDrawerButtonComponent
|
||||||
|
ToggleDrawerButton=this.toggleDrawerButtonComponent
|
||||||
|
FullPageButton=this.chatNavbarFullPageButtonComponent
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import icon from "discourse-common/helpers/d-icon";
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
export default class ChatNavbarBackButton extends Component {
|
||||||
|
get icon() {
|
||||||
|
return this.args.icon ?? "chevron-left";
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return this.args.title ?? I18n.t("chat.browse.back");
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if @routeModels}}
|
||||||
|
<LinkTo
|
||||||
|
@route={{@route}}
|
||||||
|
@models={{@routeModels}}
|
||||||
|
class="c-navbar__back-button no-text btn-flat btn"
|
||||||
|
title={{this.title}}
|
||||||
|
>
|
||||||
|
{{#if (has-block)}}
|
||||||
|
{{yield}}
|
||||||
|
{{else}}
|
||||||
|
{{icon this.icon}}
|
||||||
|
{{/if}}
|
||||||
|
</LinkTo>
|
||||||
|
{{else}}
|
||||||
|
<LinkTo
|
||||||
|
@route="chat"
|
||||||
|
class="c-navbar__back-button no-text btn-flat btn"
|
||||||
|
title={{this.title}}
|
||||||
|
>
|
||||||
|
{{#if (has-block)}}
|
||||||
|
{{yield}}
|
||||||
|
{{else}}
|
||||||
|
{{icon this.icon}}
|
||||||
|
{{/if}}
|
||||||
|
</LinkTo>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import ChannelTitle from "discourse/plugins/chat/discourse/components/channel-title";
|
||||||
|
|
||||||
|
export default class ChatNavbarChannelTitle extends Component {
|
||||||
|
<template>
|
||||||
|
{{#if @channel}}
|
||||||
|
<LinkTo
|
||||||
|
@route="chat.channel.info.members"
|
||||||
|
@models={{@channel.routeModels}}
|
||||||
|
class="c-navbar__channel-title"
|
||||||
|
>
|
||||||
|
<ChannelTitle @channel={{@channel}} />
|
||||||
|
</LinkTo>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
|
||||||
|
export default class ChatNavbarCloseDrawerButton extends Component {
|
||||||
|
@service chat;
|
||||||
|
@service chatStateManager;
|
||||||
|
|
||||||
|
@action
|
||||||
|
closeDrawer() {
|
||||||
|
this.chatStateManager.didCloseDrawer();
|
||||||
|
this.chat.activeChannel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DButton
|
||||||
|
@icon="times"
|
||||||
|
@action={{this.closeDrawer}}
|
||||||
|
@title="chat.close"
|
||||||
|
class="btn-flat no-text c-navbar__close-drawer-button"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import icon from "discourse-common/helpers/d-icon";
|
||||||
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
|
|
||||||
|
export default class ChatNavbarCloseThreadButton extends Component {
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.site.desktopView}}
|
||||||
|
<LinkTo
|
||||||
|
class="c-navbar__close-thread-button btn-flat btn btn-icon no-text"
|
||||||
|
@route="chat.channel"
|
||||||
|
@models={{@thread.channel.routeModels}}
|
||||||
|
title={{i18n "chat.thread.close"}}
|
||||||
|
>
|
||||||
|
{{icon "times"}}
|
||||||
|
</LinkTo>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import icon from "discourse-common/helpers/d-icon";
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
export default class ChatNavbarCloseThreadsButton extends Component {
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
closeButtonTitle = I18n.t("chat.thread.close");
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.site.desktopView}}
|
||||||
|
<LinkTo
|
||||||
|
class="c-navbar__close-threads-button btn-flat btn btn-icon no-text"
|
||||||
|
@route="chat.channel"
|
||||||
|
@models={{@channel.routeModels}}
|
||||||
|
title={{this.closeButtonTitle}}
|
||||||
|
>
|
||||||
|
{{icon "times"}}
|
||||||
|
</LinkTo>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { next } from "@ember/runloop";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import DiscourseURL from "discourse/lib/url";
|
||||||
|
|
||||||
|
export default class ChatNavbarFullPageButton extends Component {
|
||||||
|
@service chat;
|
||||||
|
@service chatStateManager;
|
||||||
|
|
||||||
|
@action
|
||||||
|
async openInFullPage() {
|
||||||
|
this.chatStateManager.storeAppURL();
|
||||||
|
this.chatStateManager.prefersFullPage();
|
||||||
|
this.chat.activeChannel = null;
|
||||||
|
|
||||||
|
await new Promise((resolve) => next(resolve));
|
||||||
|
|
||||||
|
DiscourseURL.routeTo(this.chatStateManager.lastKnownChatURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.chatStateManager.isDrawerExpanded}}
|
||||||
|
<DButton
|
||||||
|
@icon="discourse-expand"
|
||||||
|
class="btn-flat no-text c-navbar__full-page-button"
|
||||||
|
@title="chat.open_full_page"
|
||||||
|
@action={{this.openInFullPage}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { hash } from "@ember/helper";
|
||||||
|
import { on } from "@ember/modifier";
|
||||||
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
|
import noop from "discourse/helpers/noop";
|
||||||
|
import Actions from "./actions";
|
||||||
|
import BackButton from "./back-button";
|
||||||
|
import ChannelTitle from "./channel-title";
|
||||||
|
import Title from "./title";
|
||||||
|
|
||||||
|
export default class ChatNavbar extends Component {
|
||||||
|
get buttonComponent() {
|
||||||
|
return BackButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get titleComponent() {
|
||||||
|
return Title;
|
||||||
|
}
|
||||||
|
|
||||||
|
get actionsComponent() {
|
||||||
|
return Actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
get channelTitleComponent() {
|
||||||
|
return ChannelTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{! template-lint-disable no-invalid-interactive }}
|
||||||
|
<div
|
||||||
|
class={{concatClass "c-navbar-container" (if @onClick "-clickable")}}
|
||||||
|
{{on "click" (if @onClick @onClick (noop))}}
|
||||||
|
>
|
||||||
|
<nav class="c-navbar">
|
||||||
|
{{yield
|
||||||
|
(hash
|
||||||
|
BackButton=this.buttonComponent
|
||||||
|
ChannelTitle=this.channelTitleComponent
|
||||||
|
Title=this.titleComponent
|
||||||
|
Actions=this.actionsComponent
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
|
import CreateChannelModal from "discourse/plugins/chat/discourse/components/chat/modal/create-channel";
|
||||||
|
|
||||||
|
export default class ChatNavbarNewChannelButton extends Component {
|
||||||
|
@service chatStateManager;
|
||||||
|
@service currentUser;
|
||||||
|
@service modal;
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
@action
|
||||||
|
createChannel() {
|
||||||
|
this.modal.show(CreateChannelModal);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.currentUser.staff}}
|
||||||
|
<DButton
|
||||||
|
@action={{this.createChannel}}
|
||||||
|
@icon="plus"
|
||||||
|
@label={{if this.site.desktopView "chat.create_channel.title"}}
|
||||||
|
class={{concatClass
|
||||||
|
"c-navbar__new-channel-button"
|
||||||
|
(if this.site.mobileView "btn-flat")
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import DiscourseURL from "discourse/lib/url";
|
||||||
|
|
||||||
|
export default class ChatNavbarOpenDrawerButton extends Component {
|
||||||
|
@service chatStateManager;
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
@action
|
||||||
|
async openDrawer() {
|
||||||
|
this.chatStateManager.prefersDrawer();
|
||||||
|
|
||||||
|
DiscourseURL.routeTo(this.chatStateManager.lastKnownAppURL).then(() => {
|
||||||
|
DiscourseURL.routeTo(this.chatStateManager.lastKnownChatURL);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.site.desktopView}}
|
||||||
|
<DButton
|
||||||
|
@icon="discourse-compress"
|
||||||
|
@title="chat.close_full_page"
|
||||||
|
class="c-navbar__open-drawer-button btn-flat"
|
||||||
|
@action={{this.openDrawer}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import SubTitle from "./sub-title";
|
||||||
|
|
||||||
|
export default class ChatNavbarSubTitle extends Component {
|
||||||
|
get subTitleComponent() {
|
||||||
|
return SubTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-navbar__sub-title">
|
||||||
|
{{#if (has-block)}}
|
||||||
|
{{yield}}
|
||||||
|
{{else}}
|
||||||
|
{{@title}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import ThreadSettingsModal from "discourse/plugins/chat/discourse/components/chat/modal/thread-settings";
|
||||||
|
|
||||||
|
export default class ChatNavbarThreadSettingsButton extends Component {
|
||||||
|
@service currentUser;
|
||||||
|
@service modal;
|
||||||
|
|
||||||
|
get canChangeThreadSettings() {
|
||||||
|
if (!this.args.thread) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.currentUser.staff ||
|
||||||
|
this.currentUser.id === this.args.thread.originalMessage.user.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
openThreadSettings() {
|
||||||
|
this.modal.show(ThreadSettingsModal, { model: this.args.thread });
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.canChangeThreadSettings}}
|
||||||
|
<DButton
|
||||||
|
@action={{this.openThreadSettings}}
|
||||||
|
@icon="cog"
|
||||||
|
@title="chat.thread.settings"
|
||||||
|
class="btn-flat c-navbar__thread-settings-button"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||||
|
import ThreadTrackingDropdown from "discourse/plugins/chat/discourse/components/chat-thread-tracking-dropdown";
|
||||||
|
import UserChatThreadMembership from "discourse/plugins/chat/discourse/models/user-chat-thread-membership";
|
||||||
|
|
||||||
|
export default class ChatNavbarThreadTrackingDropdown extends Component {
|
||||||
|
@service chatApi;
|
||||||
|
|
||||||
|
@tracked persistedNotificationLevel = true;
|
||||||
|
|
||||||
|
get threadNotificationLevel() {
|
||||||
|
return this.membership?.notificationLevel || NotificationLevels.REGULAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
get membership() {
|
||||||
|
return this.args.thread.currentUserMembership;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async updateThreadNotificationLevel(newNotificationLevel) {
|
||||||
|
this.persistedNotificationLevel = false;
|
||||||
|
|
||||||
|
let currentNotificationLevel;
|
||||||
|
|
||||||
|
if (this.membership) {
|
||||||
|
currentNotificationLevel = this.membership.notificationLevel;
|
||||||
|
this.membership.notificationLevel = newNotificationLevel;
|
||||||
|
} else {
|
||||||
|
this.args.thread.currentUserMembership = UserChatThreadMembership.create({
|
||||||
|
notification_level: newNotificationLevel,
|
||||||
|
last_read_message_id: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response =
|
||||||
|
await this.chatApi.updateCurrentUserThreadNotificationsSettings(
|
||||||
|
this.args.thread.channel.id,
|
||||||
|
this.args.thread.id,
|
||||||
|
{ notificationLevel: newNotificationLevel }
|
||||||
|
);
|
||||||
|
this.membership.last_read_message_id =
|
||||||
|
response.membership.last_read_message_id;
|
||||||
|
this.persistedNotificationLevel = true;
|
||||||
|
} catch (error) {
|
||||||
|
this.membership.notificationLevel = currentNotificationLevel;
|
||||||
|
popupAjaxError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ThreadTrackingDropdown
|
||||||
|
@value={{this.threadNotificationLevel}}
|
||||||
|
@onChange={{this.updateThreadNotificationLevel}}
|
||||||
|
@class={{concatClass
|
||||||
|
"c-navbar__thread-tracking-dropdown"
|
||||||
|
(if this.persistedNotificationLevel "-persisted")
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
|
import icon from "discourse-common/helpers/d-icon";
|
||||||
|
import I18n from "I18n";
|
||||||
|
import ThreadHeaderUnreadIndicator from "discourse/plugins/chat/discourse/components/chat/thread/header-unread-indicator";
|
||||||
|
|
||||||
|
export default class ChatNavbarThreadsListButton extends Component {
|
||||||
|
@service router;
|
||||||
|
|
||||||
|
threadsListLabel = I18n.t("chat.threads.list");
|
||||||
|
|
||||||
|
get showThreadsListButton() {
|
||||||
|
return (
|
||||||
|
this.args.channel?.threadingEnabled &&
|
||||||
|
this.router.currentRoute.name !== "chat.channel.threads" &&
|
||||||
|
this.router.currentRoute.name !== "chat.channel.thread" &&
|
||||||
|
this.router.currentRoute.name !== "chat.channel.thread.index"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.showThreadsListButton}}
|
||||||
|
<LinkTo
|
||||||
|
@route="chat.channel.threads"
|
||||||
|
@models={{@channel.routeModels}}
|
||||||
|
title={{this.threadsListLabel}}
|
||||||
|
class={{concatClass
|
||||||
|
"c-navbar__threads-list-button"
|
||||||
|
"btn"
|
||||||
|
"no-text"
|
||||||
|
"btn-flat"
|
||||||
|
(if @channel.threadsManager.unreadThreadCount "has-unreads")
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{{icon "discourse-threads"}}
|
||||||
|
<ThreadHeaderUnreadIndicator @channel={{@channel}} />
|
||||||
|
</LinkTo>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { hash } from "@ember/helper";
|
||||||
|
import icon from "discourse-common/helpers/d-icon";
|
||||||
|
import SubTitle from "./sub-title";
|
||||||
|
|
||||||
|
export default class ChatNavbarTitle extends Component {
|
||||||
|
get subTitleComponent() {
|
||||||
|
return SubTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-navbar__title">
|
||||||
|
{{#if (has-block)}}
|
||||||
|
{{#if @icon}}
|
||||||
|
{{icon @icon}}
|
||||||
|
{{/if}}
|
||||||
|
{{@title}}
|
||||||
|
{{yield (hash SubTitle=this.subTitleComponent)}}
|
||||||
|
{{else}}
|
||||||
|
{{#if @icon}}
|
||||||
|
{{icon @icon}}
|
||||||
|
{{/if}}
|
||||||
|
{{@title}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -2,7 +2,8 @@ import Component from "@glimmer/component";
|
|||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import DButton from "discourse/components/d-button";
|
import DButton from "discourse/components/d-button";
|
||||||
|
|
||||||
export default class ChatDrawerHeaderToggleExpandButton extends Component {
|
export default class ChatNavbarToggleDrawerButton extends Component {
|
||||||
|
@service chat;
|
||||||
@service chatStateManager;
|
@service chatStateManager;
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -12,13 +13,13 @@ export default class ChatDrawerHeaderToggleExpandButton extends Component {
|
|||||||
"angle-double-down"
|
"angle-double-down"
|
||||||
"angle-double-up"
|
"angle-double-up"
|
||||||
}}
|
}}
|
||||||
@action={{@toggleExpand}}
|
@action={{this.chat.toggleDrawer}}
|
||||||
@title={{if
|
@title={{if
|
||||||
this.chatStateManager.isDrawerExpanded
|
this.chatStateManager.isDrawerExpanded
|
||||||
"chat.collapse"
|
"chat.collapse"
|
||||||
"chat.expand"
|
"chat.expand"
|
||||||
}}
|
}}
|
||||||
class="btn-flat btn-link chat-drawer-header__expand-btn"
|
class="btn-flat no-text c-navbar__toggle-drawer-button"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
}
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
import { cached, tracked } from "@glimmer/tracking";
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { concat, hash } from "@ember/helper";
|
||||||
|
import { action, computed } from "@ember/object";
|
||||||
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import { schedule } from "@ember/runloop";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
|
import List from "discourse/plugins/chat/discourse/components/chat/list";
|
||||||
|
import ChatModalNewMessage from "discourse/plugins/chat/discourse/components/chat/modal/new-message";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
import ChatChannelCard from "discourse/plugins/chat/discourse/components/chat-channel-card";
|
||||||
|
import DcFilterInput from "discourse/plugins/chat/discourse/components/dc-filter-input";
|
||||||
|
|
||||||
|
const TABS = ["all", "open", "closed", "archived"];
|
||||||
|
|
||||||
|
export default class ChatRoutesBrowse extends Component {
|
||||||
|
@service chatApi;
|
||||||
|
@service modal;
|
||||||
|
|
||||||
|
@tracked filter = "";
|
||||||
|
|
||||||
|
@cached
|
||||||
|
get channelsCollection() {
|
||||||
|
return this.chatApi.channels({
|
||||||
|
filter: this.filter,
|
||||||
|
status: this.attrs.status,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed("siteSettings.chat_allow_archiving_channels")
|
||||||
|
get tabs() {
|
||||||
|
if (this.siteSettings.chat_allow_archiving_channels) {
|
||||||
|
return TABS;
|
||||||
|
} else {
|
||||||
|
return [...TABS].removeObject("archived");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
showChatNewMessageModal() {
|
||||||
|
this.modal.show(ChatModalNewMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setFilter(event) {
|
||||||
|
this.filter = event.target.value;
|
||||||
|
discourseDebounce(this.debouncedLoad, INPUT_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
debouncedLoad() {
|
||||||
|
this.channelsCollection.load({ limit: 10 });
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
focusFilterInput(input) {
|
||||||
|
schedule("afterRender", () => input?.focus());
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-routes-browse">
|
||||||
|
<Navbar as |navbar|>
|
||||||
|
<navbar.BackButton />
|
||||||
|
<navbar.Title @title={{i18n "chat.browse.title"}} />
|
||||||
|
|
||||||
|
<navbar.Actions as |action|>
|
||||||
|
<action.NewChannelButton />
|
||||||
|
</navbar.Actions>
|
||||||
|
</Navbar>
|
||||||
|
|
||||||
|
<div class="chat-browse-view">
|
||||||
|
<div class="chat-browse-view__actions">
|
||||||
|
<nav>
|
||||||
|
<ul class="nav-pills chat-browse-view__filters">
|
||||||
|
{{#each this.tabs as |tab|}}
|
||||||
|
<li class={{concat "chat-browse-view__filter -" tab}}>
|
||||||
|
<LinkTo
|
||||||
|
@route={{concat "chat.browse." tab}}
|
||||||
|
class={{concat "chat-browse-view__filter-link -" tab}}
|
||||||
|
>
|
||||||
|
{{i18n (concat "chat.browse.filter_" tab)}}
|
||||||
|
</LinkTo>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<DcFilterInput
|
||||||
|
{{didInsert this.focusFilterInput}}
|
||||||
|
@filterAction={{this.setFilter}}
|
||||||
|
@icons={{hash right="search"}}
|
||||||
|
@containerClass="filter-input"
|
||||||
|
placeholder={{i18n "chat.browse.filter_input_placeholder"}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-browse-view__content_wrapper">
|
||||||
|
<div class="chat-browse-view__content">
|
||||||
|
<List
|
||||||
|
@collection={{this.channelsCollection}}
|
||||||
|
class="chat-browse-view__cards"
|
||||||
|
as |list|
|
||||||
|
>
|
||||||
|
<list.Item as |channel|>
|
||||||
|
<ChatChannelCard @channel={{channel}} />
|
||||||
|
</list.Item>
|
||||||
|
|
||||||
|
<list.EmptyState>
|
||||||
|
<span class="empty-state-title">
|
||||||
|
{{i18n "chat.empty_state.title"}}
|
||||||
|
</span>
|
||||||
|
<div class="empty-state-body">
|
||||||
|
<p>{{i18n "chat.empty_state.direct_message"}}</p>
|
||||||
|
<DButton
|
||||||
|
@action={{this.showChatNewMessageModal}}
|
||||||
|
@label="chat.empty_state.direct_message_cta"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</list.EmptyState>
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -13,11 +13,11 @@ import icon from "discourse-common/helpers/d-icon";
|
|||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
import MessageCreator from "discourse/plugins/chat/discourse/components/chat/message-creator";
|
import MessageCreator from "discourse/plugins/chat/discourse/components/chat/message-creator";
|
||||||
|
import { MODES } from "discourse/plugins/chat/discourse/components/chat/message-creator/constants";
|
||||||
import ChatUserInfo from "discourse/plugins/chat/discourse/components/chat-user-info";
|
import ChatUserInfo from "discourse/plugins/chat/discourse/components/chat-user-info";
|
||||||
import DcFilterInput from "discourse/plugins/chat/discourse/components/dc-filter-input";
|
import DcFilterInput from "discourse/plugins/chat/discourse/components/dc-filter-input";
|
||||||
import { MODES } from "./chat/message-creator/constants";
|
|
||||||
|
|
||||||
export default class ChatChannelMembers extends Component {
|
export default class ChatRouteChannelInfoMembers extends Component {
|
||||||
@service appEvents;
|
@service appEvents;
|
||||||
@service chatApi;
|
@service chatApi;
|
||||||
@service modal;
|
@service modal;
|
@ -28,7 +28,7 @@ const NOTIFICATION_LEVELS = [
|
|||||||
{ name: I18n.t("chat.notification_levels.always"), value: "always" },
|
{ name: I18n.t("chat.notification_levels.always"), value: "always" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default class ChatAboutScreen extends Component {
|
export default class ChatRouteChannelInfoSettings extends Component {
|
||||||
@service chatApi;
|
@service chatApi;
|
||||||
@service chatGuardian;
|
@service chatGuardian;
|
||||||
@service chatChannelsManager;
|
@service chatChannelsManager;
|
@ -0,0 +1,91 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { LinkTo } from "@ember/routing";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import I18n from "discourse-i18n";
|
||||||
|
import ChatModalEditChannelName from "discourse/plugins/chat/discourse/components/chat/modal/edit-channel-name";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
import ChatChannelStatus from "discourse/plugins/chat/discourse/components/chat-channel-status";
|
||||||
|
|
||||||
|
export default class ChatRoutesChannelInfo extends Component {
|
||||||
|
@service chatChannelInfoRouteOriginManager;
|
||||||
|
@service site;
|
||||||
|
@service modal;
|
||||||
|
@service chatGuardian;
|
||||||
|
|
||||||
|
membersLabel = I18n.t("chat.channel_info.tabs.members");
|
||||||
|
settingsLabel = I18n.t("chat.channel_info.tabs.settings");
|
||||||
|
backToChannelLabel = I18n.t("chat.channel_info.back_to_all_channel");
|
||||||
|
backToAllChannelsLabel = I18n.t("chat.channel_info.back_to_channel");
|
||||||
|
|
||||||
|
get showTabs() {
|
||||||
|
return this.site.desktopView && this.args.channel.isOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canEditChannel() {
|
||||||
|
return (
|
||||||
|
this.chatGuardian.canEditChatChannel() &&
|
||||||
|
(this.args.channel.isCategoryChannel ||
|
||||||
|
(this.args.channel.isDirectMessageChannel &&
|
||||||
|
this.args.channel.chatable.group))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
editChannelTitle() {
|
||||||
|
return this.modal.show(ChatModalEditChannelName, {
|
||||||
|
model: this.args.channel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-routes-channel-info">
|
||||||
|
<Navbar as |navbar|>
|
||||||
|
{{#if this.chatChannelInfoRouteOriginManager.isBrowse}}
|
||||||
|
<navbar.BackButton
|
||||||
|
@route="chat.browse"
|
||||||
|
@title={{this.backToAllChannelsLabel}}
|
||||||
|
/>
|
||||||
|
{{else}}
|
||||||
|
<navbar.BackButton
|
||||||
|
@route="chat.channel"
|
||||||
|
@routeModels={{@channel.routeModels}}
|
||||||
|
@title={{this.backToChannelLabel}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
<navbar.ChannelTitle @channel={{@channel}} />
|
||||||
|
</Navbar>
|
||||||
|
|
||||||
|
<ChatChannelStatus @channel={{@channel}} />
|
||||||
|
|
||||||
|
<div class="chat-channel-info">
|
||||||
|
{{#if this.showTabs}}
|
||||||
|
<nav class="chat-channel-info__nav">
|
||||||
|
<ul class="nav nav-pills">
|
||||||
|
<li>
|
||||||
|
<LinkTo
|
||||||
|
@route="chat.channel.info.settings"
|
||||||
|
@model={{@channel}}
|
||||||
|
@replace={{true}}
|
||||||
|
>
|
||||||
|
{{this.settingsLabel}}
|
||||||
|
</LinkTo>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<LinkTo
|
||||||
|
@route="chat.channel.info.members"
|
||||||
|
@model={{@channel}}
|
||||||
|
@replace={{true}}
|
||||||
|
>
|
||||||
|
{{this.membersLabel}}
|
||||||
|
</LinkTo>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{outlet}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { array } from "@ember/helper";
|
||||||
|
import ThreadHeader from "discourse/plugins/chat/discourse/components/chat/thread/header";
|
||||||
|
import Thread from "discourse/plugins/chat/discourse/components/chat-thread";
|
||||||
|
|
||||||
|
export default class ChatRoutesChannelThread extends Component {
|
||||||
|
<template>
|
||||||
|
<div class="c-routes-channel-thread">
|
||||||
|
{{#each (array @thread) as |thread|}}
|
||||||
|
<ThreadHeader @thread={{thread}} />
|
||||||
|
|
||||||
|
<Thread
|
||||||
|
@thread={{thread}}
|
||||||
|
@targetMessageId={{@targetMessageId}}
|
||||||
|
@includeHeader={{true}}
|
||||||
|
/>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import ChatThreadListHeader from "discourse/plugins/chat/discourse/components/chat/thread-list/header";
|
||||||
|
import ChatThreadList from "discourse/plugins/chat/discourse/components/chat-thread-list";
|
||||||
|
|
||||||
|
export default class ChatRoutesChannelThreads extends Component {
|
||||||
|
<template>
|
||||||
|
<div class="c-routes-channel-threads">
|
||||||
|
<ChatThreadListHeader @channel={{@channel}} />
|
||||||
|
<ChatThreadList @channel={{@channel}} @includeHeader={{true}} />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
import SidePanel from "discourse/plugins/chat/discourse/components/chat-side-panel";
|
||||||
|
import FullPageChat from "discourse/plugins/chat/discourse/components/full-page-chat";
|
||||||
|
|
||||||
|
export default class ChatRoutesChannel extends Component {
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-routes-channel">
|
||||||
|
<Navbar as |navbar|>
|
||||||
|
{{#if this.site.mobileView}}
|
||||||
|
<navbar.BackButton />
|
||||||
|
{{/if}}
|
||||||
|
<navbar.ChannelTitle @channel={{@channel}} />
|
||||||
|
<navbar.Actions as |action|>
|
||||||
|
<action.OpenDrawerButton />
|
||||||
|
<action.ThreadsListButton @channel={{@channel}} />
|
||||||
|
</navbar.Actions>
|
||||||
|
</Navbar>
|
||||||
|
|
||||||
|
<FullPageChat
|
||||||
|
@channel={{@channel}}
|
||||||
|
@targetMessageId={{@targetMessageId}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SidePanel>
|
||||||
|
{{outlet}}
|
||||||
|
</SidePanel>
|
||||||
|
</template>
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
import UserThreads from "discourse/plugins/chat/discourse/components/user-threads";
|
||||||
|
|
||||||
|
export default class ChatRoutesThreads extends Component {
|
||||||
|
<template>
|
||||||
|
<div class="c-routes-threads">
|
||||||
|
<Navbar as |navbar|>
|
||||||
|
<navbar.BackButton />
|
||||||
|
<navbar.Title
|
||||||
|
@title={{i18n "chat.my_threads.title"}}
|
||||||
|
@icon="discourse-threads"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<navbar.Actions as |action|>
|
||||||
|
<action.OpenDrawerButton />
|
||||||
|
</navbar.Actions>
|
||||||
|
</Navbar>
|
||||||
|
|
||||||
|
<UserThreads />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
}
|
@ -1,70 +1,37 @@
|
|||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { LinkTo } from "@ember/routing";
|
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||||
import icon from "discourse-common/helpers/d-icon";
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
|
|
||||||
export default class ChatThreadListHeader extends Component {
|
export default class ChatThreadListHeader extends Component {
|
||||||
@service router;
|
@service router;
|
||||||
@service site;
|
@service site;
|
||||||
|
|
||||||
threadListTitle = I18n.t("chat.threads.list");
|
threadListTitle = I18n.t("chat.threads.list");
|
||||||
closeButtonTitle = I18n.t("chat.thread.close");
|
|
||||||
showCloseButton = !this.site.mobileView;
|
|
||||||
|
|
||||||
get showBackButton() {
|
|
||||||
return this.args.channel && this.site.mobileView;
|
|
||||||
}
|
|
||||||
|
|
||||||
get backButton() {
|
|
||||||
return {
|
|
||||||
route: "chat.channel.index",
|
|
||||||
models: this.args.channel.routeModels,
|
|
||||||
title: I18n.t("chat.return_to_channel"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chat-thread-list-header">
|
<Navbar as |navbar|>
|
||||||
<div class="chat-thread-header__left-buttons">
|
<navbar.BackButton
|
||||||
{{#if this.showBackButton}}
|
|
||||||
<LinkTo
|
|
||||||
class="chat-thread__back-to-previous-route btn-flat btn btn-icon no-text"
|
|
||||||
@route={{this.backButton.route}}
|
|
||||||
@models={{this.backButton.models}}
|
|
||||||
title={{this.backButton.title}}
|
|
||||||
>
|
|
||||||
{{icon "chevron-left"}}
|
|
||||||
</LinkTo>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="chat-thread-list-header__label">
|
|
||||||
<span>
|
|
||||||
{{icon "discourse-threads"}}
|
|
||||||
{{replaceEmoji this.threadListTitle}}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{{#if this.site.mobileView}}
|
|
||||||
<div class="chat-thread-list-header__label-channel">
|
|
||||||
{{replaceEmoji @channel.title}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if this.showCloseButton}}
|
|
||||||
<div class="chat-thread-header__buttons">
|
|
||||||
<LinkTo
|
|
||||||
class="chat-thread__close btn-flat btn btn-icon no-text"
|
|
||||||
@route="chat.channel"
|
@route="chat.channel"
|
||||||
@models={{@channel.routeModels}}
|
@routeModels={{@channel.routeModels}}
|
||||||
title={{this.closeButtonTitle}}
|
@title={{i18n "chat.return_to_channel"}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<navbar.Title
|
||||||
|
@title={{replaceEmoji this.threadListTitle}}
|
||||||
|
@icon="discourse-threads"
|
||||||
|
as |title|
|
||||||
>
|
>
|
||||||
{{icon "times"}}
|
{{#if this.site.mobileView}}
|
||||||
</LinkTo>
|
<title.SubTitle @title={{replaceEmoji @channel.title}} />
|
||||||
</div>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</navbar.Title>
|
||||||
|
|
||||||
|
<navbar.Actions as |action|>
|
||||||
|
<action.CloseThreadsButton @channel={{@channel}} />
|
||||||
|
</navbar.Actions>
|
||||||
|
</Navbar>
|
||||||
</template>
|
</template>
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ export default class ChatThreadListItem extends Component {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chat-thread-list-item__metadata">
|
<div class="chat-thread-list-item__metadata">
|
||||||
|
|
||||||
<div class="chat-thread-list-item__members">
|
<div class="chat-thread-list-item__members">
|
||||||
<ChatUserAvatar
|
<ChatUserAvatar
|
||||||
@user={{@thread.originalMessage.user}}
|
@user={{@thread.originalMessage.user}}
|
||||||
@ -72,7 +71,6 @@ export default class ChatThreadListItem extends Component {
|
|||||||
}}
|
}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,32 +1,15 @@
|
|||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { tracked } from "@glimmer/tracking";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { LinkTo } from "@ember/routing";
|
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import DButton from "discourse/components/d-button";
|
|
||||||
import concatClass from "discourse/helpers/concat-class";
|
|
||||||
import replaceEmoji from "discourse/helpers/replace-emoji";
|
import replaceEmoji from "discourse/helpers/replace-emoji";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
||||||
import { NotificationLevels } from "discourse/lib/notification-levels";
|
|
||||||
import icon from "discourse-common/helpers/d-icon";
|
import icon from "discourse-common/helpers/d-icon";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
import ChatModalThreadSettings from "discourse/plugins/chat/discourse/components/chat/modal/thread-settings";
|
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||||
import ChatThreadHeaderUnreadIndicator from "discourse/plugins/chat/discourse/components/chat/thread/header-unread-indicator";
|
import ChatThreadHeaderUnreadIndicator from "discourse/plugins/chat/discourse/components/chat/thread/header-unread-indicator";
|
||||||
import UserChatThreadMembership from "discourse/plugins/chat/discourse/models/user-chat-thread-membership";
|
|
||||||
import ThreadNotificationsButton from "discourse/plugins/chat/select-kit/addons/components/thread-notifications-button";
|
|
||||||
|
|
||||||
export default class ChatThreadHeader extends Component {
|
export default class ChatThreadHeader extends Component {
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
@service chatApi;
|
|
||||||
@service router;
|
|
||||||
@service chatStateManager;
|
|
||||||
@service chatHistory;
|
@service chatHistory;
|
||||||
@service site;
|
@service site;
|
||||||
@service modal;
|
|
||||||
|
|
||||||
@tracked persistedNotificationLevel = true;
|
|
||||||
|
|
||||||
closeThreadTitle = I18n.t("chat.thread.close");
|
|
||||||
|
|
||||||
get backLink() {
|
get backLink() {
|
||||||
const prevPage = this.chatHistory.previousRoute?.name;
|
const prevPage = this.chatHistory.previousRoute?.name;
|
||||||
@ -35,15 +18,15 @@ export default class ChatThreadHeader extends Component {
|
|||||||
if (prevPage === "chat.channel.threads") {
|
if (prevPage === "chat.channel.threads") {
|
||||||
route = "chat.channel.threads";
|
route = "chat.channel.threads";
|
||||||
title = I18n.t("chat.return_to_threads_list");
|
title = I18n.t("chat.return_to_threads_list");
|
||||||
models = this.args.channel.routeModels;
|
models = this.channel?.routeModels;
|
||||||
} else if (prevPage === "chat.channel.index" && !this.site.mobileView) {
|
} else if (prevPage === "chat.channel.index" && !this.site.mobileView) {
|
||||||
route = "chat.channel.threads";
|
route = "chat.channel.threads";
|
||||||
title = I18n.t("chat.return_to_threads_list");
|
title = I18n.t("chat.return_to_threads_list");
|
||||||
models = this.args.channel.routeModels;
|
models = this.channel?.routeModels;
|
||||||
} else if (!this.currentUser.isInDoNotDisturb() && this.unreadCount > 0) {
|
} else if (!this.currentUser.isInDoNotDisturb() && this.unreadCount > 0) {
|
||||||
route = "chat.channel.threads";
|
route = "chat.channel.threads";
|
||||||
title = I18n.t("chat.return_to_threads_list");
|
title = I18n.t("chat.return_to_threads_list");
|
||||||
models = this.args.channel.routeModels;
|
models = this.channel?.routeModels;
|
||||||
} else if (prevPage === "chat.threads") {
|
} else if (prevPage === "chat.threads") {
|
||||||
route = "chat.threads";
|
route = "chat.threads";
|
||||||
title = I18n.t("chat.my_threads.title");
|
title = I18n.t("chat.my_threads.title");
|
||||||
@ -51,29 +34,14 @@ export default class ChatThreadHeader extends Component {
|
|||||||
} else {
|
} else {
|
||||||
route = "chat.channel.index";
|
route = "chat.channel.index";
|
||||||
title = I18n.t("chat.return_to_channel");
|
title = I18n.t("chat.return_to_channel");
|
||||||
models = this.args.channel.routeModels;
|
models = this.channel?.routeModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { route, models, title };
|
return { route, models, title };
|
||||||
}
|
}
|
||||||
|
|
||||||
get canChangeThreadSettings() {
|
get channel() {
|
||||||
if (!this.args.thread) {
|
return this.args.thread?.channel;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
this.currentUser.staff ||
|
|
||||||
this.currentUser.id === this.args.thread.originalMessage.user.id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get threadNotificationLevel() {
|
|
||||||
return this.membership?.notificationLevel || NotificationLevels.REGULAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
get membership() {
|
|
||||||
return this.args.thread.currentUserMembership;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get headerTitle() {
|
get headerTitle() {
|
||||||
@ -81,97 +49,28 @@ export default class ChatThreadHeader extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get unreadCount() {
|
get unreadCount() {
|
||||||
return this.args.channel.threadsManager.unreadThreadCount;
|
return this.channel?.threadsManager?.unreadThreadCount;
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
openThreadSettings() {
|
|
||||||
this.modal.show(ChatModalThreadSettings, { model: this.args.thread });
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
updateThreadNotificationLevel(newNotificationLevel) {
|
|
||||||
this.persistedNotificationLevel = false;
|
|
||||||
|
|
||||||
let currentNotificationLevel;
|
|
||||||
|
|
||||||
if (this.membership) {
|
|
||||||
currentNotificationLevel = this.membership.notificationLevel;
|
|
||||||
this.membership.notificationLevel = newNotificationLevel;
|
|
||||||
} else {
|
|
||||||
this.args.thread.currentUserMembership = UserChatThreadMembership.create({
|
|
||||||
notification_level: newNotificationLevel,
|
|
||||||
last_read_message_id: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.chatApi
|
|
||||||
.updateCurrentUserThreadNotificationsSettings(
|
|
||||||
this.args.thread.channel.id,
|
|
||||||
this.args.thread.id,
|
|
||||||
{ notificationLevel: newNotificationLevel }
|
|
||||||
)
|
|
||||||
.then((response) => {
|
|
||||||
this.membership.last_read_message_id =
|
|
||||||
response.membership.last_read_message_id;
|
|
||||||
|
|
||||||
this.persistedNotificationLevel = true;
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
this.membership.notificationLevel = currentNotificationLevel;
|
|
||||||
popupAjaxError(err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chat-thread-header">
|
<Navbar as |navbar|>
|
||||||
<div class="chat-thread-header__left-buttons">
|
|
||||||
{{#if @thread}}
|
{{#if @thread}}
|
||||||
<LinkTo
|
<navbar.BackButton
|
||||||
class="chat-thread__back-to-previous-route btn-flat btn btn-icon no-text"
|
|
||||||
@route={{this.backLink.route}}
|
@route={{this.backLink.route}}
|
||||||
@models={{this.backLink.models}}
|
@routeModels={{this.backLink.models}}
|
||||||
title={{this.backLink.title}}
|
@title={{this.backLink.title}}
|
||||||
>
|
>
|
||||||
<ChatThreadHeaderUnreadIndicator @channel={{@thread.channel}} />
|
<ChatThreadHeaderUnreadIndicator @channel={{this.channel}} />
|
||||||
{{icon "chevron-left"}}
|
{{icon "chevron-left"}}
|
||||||
</LinkTo>
|
</navbar.BackButton>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
|
||||||
|
|
||||||
<span class="chat-thread-header__label overflow-ellipsis">
|
<navbar.Title @title={{replaceEmoji this.headerTitle}} />
|
||||||
{{replaceEmoji this.headerTitle}}
|
<navbar.Actions as |action|>
|
||||||
</span>
|
<action.ThreadTrackingDropdown @thread={{@thread}} />
|
||||||
|
<action.ThreadSettingsButton @thread={{@thread}} />
|
||||||
<div
|
<action.CloseThreadButton @thread={{@thread}} />
|
||||||
class={{concatClass
|
</navbar.Actions>
|
||||||
"chat-thread-header__buttons"
|
</Navbar>
|
||||||
(if this.persistedNotificationLevel "-persisted")
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ThreadNotificationsButton
|
|
||||||
@value={{this.threadNotificationLevel}}
|
|
||||||
@onChange={{this.updateThreadNotificationLevel}}
|
|
||||||
/>
|
|
||||||
{{#if this.canChangeThreadSettings}}
|
|
||||||
<DButton
|
|
||||||
@action={{this.openThreadSettings}}
|
|
||||||
@icon="cog"
|
|
||||||
@title="chat.thread.settings"
|
|
||||||
class="btn-flat chat-thread-header__settings"
|
|
||||||
/>
|
|
||||||
{{/if}}
|
|
||||||
{{#unless this.site.mobileView}}
|
|
||||||
<LinkTo
|
|
||||||
class="chat-thread__close btn-flat btn btn-icon no-text"
|
|
||||||
@route="chat.channel"
|
|
||||||
@models={{@thread.channel.routeModels}}
|
|
||||||
title={{this.closeThreadTitle}}
|
|
||||||
>
|
|
||||||
{{icon "times"}}
|
|
||||||
</LinkTo>
|
|
||||||
{{/unless}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { LinkTo } from "@ember/routing";
|
|
||||||
import concatClass from "discourse/helpers/concat-class";
|
|
||||||
import icon from "discourse-common/helpers/d-icon";
|
|
||||||
import I18n from "I18n";
|
|
||||||
import ThreadHeaderUnreadIndicator from "discourse/plugins/chat/discourse/components/chat/thread/header-unread-indicator";
|
|
||||||
|
|
||||||
export default class ThreadsListButton extends Component {
|
|
||||||
threadsListLabel = I18n.t("chat.threads.list");
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<LinkTo
|
|
||||||
@route="chat.channel.threads"
|
|
||||||
@models={{@channel.routeModels}}
|
|
||||||
title={{this.threadsListLabel}}
|
|
||||||
class={{concatClass
|
|
||||||
"chat-threads-list-button"
|
|
||||||
"btn"
|
|
||||||
"btn-flat"
|
|
||||||
(if @channel.threadsManager.unreadThreadCount "has-unreads")
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{{icon "discourse-threads"}}
|
|
||||||
|
|
||||||
<ThreadHeaderUnreadIndicator @channel={{@channel}} />
|
|
||||||
</LinkTo>
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import icon from "discourse-common/helpers/d-icon";
|
|
||||||
import i18n from "discourse-common/helpers/i18n";
|
|
||||||
import Navbar from "discourse/plugins/chat/discourse/components/navbar";
|
|
||||||
import UserThreads from "discourse/plugins/chat/discourse/components/user-threads";
|
|
||||||
|
|
||||||
export default class ChatThreads extends Component {
|
|
||||||
<template>
|
|
||||||
<div class="chat-threads">
|
|
||||||
<Navbar>
|
|
||||||
<:current>
|
|
||||||
{{icon "discourse-threads"}}
|
|
||||||
{{i18n "chat.my_threads.title"}}
|
|
||||||
</:current>
|
|
||||||
</Navbar>
|
|
||||||
|
|
||||||
<UserThreads />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
import Component from "@glimmer/component";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import DButton from "discourse/components/d-button";
|
|
||||||
import DiscourseURL from "discourse/lib/url";
|
|
||||||
|
|
||||||
export default class ChatNavbar extends Component {
|
|
||||||
@service chatStateManager;
|
|
||||||
|
|
||||||
@action
|
|
||||||
async closeFullScreen() {
|
|
||||||
this.chatStateManager.prefersDrawer();
|
|
||||||
|
|
||||||
try {
|
|
||||||
await DiscourseURL.routeTo(this.chatStateManager.lastKnownAppURL);
|
|
||||||
await DiscourseURL.routeTo(this.chatStateManager.lastKnownChatURL);
|
|
||||||
} catch (error) {
|
|
||||||
await DiscourseURL.routeTo("/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="chat-navbar-container">
|
|
||||||
<nav class="chat-navbar">
|
|
||||||
{{#if (has-block "current")}}
|
|
||||||
<span class="chat-navbar__current">
|
|
||||||
{{yield to="current"}}
|
|
||||||
</span>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<ul class="chat-navbar__right-actions">
|
|
||||||
<li class="chat-navbar__right-action">
|
|
||||||
<DButton
|
|
||||||
@icon="discourse-compress"
|
|
||||||
@title="chat.close_full_page"
|
|
||||||
class="open-drawer-btn btn-flat"
|
|
||||||
@action={{this.closeFullScreen}}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
}
|
|
@ -1,14 +1,9 @@
|
|||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { cached } from "@glimmer/tracking";
|
import { cached } from "@glimmer/tracking";
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import { modifier } from "ember-modifier";
|
|
||||||
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
|
||||||
import isElementInViewport from "discourse/lib/is-element-in-viewport";
|
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
|
||||||
import { bind } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import ChannelTitle from "discourse/plugins/chat/discourse/components/channel-title";
|
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 ThreadIndicator from "discourse/plugins/chat/discourse/components/chat-message-thread-indicator";
|
||||||
import ThreadTitle from "discourse/plugins/chat/discourse/components/thread-title";
|
import ThreadTitle from "discourse/plugins/chat/discourse/components/thread-title";
|
||||||
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
|
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||||
@ -17,45 +12,12 @@ import ChatThread from "discourse/plugins/chat/discourse/models/chat-thread";
|
|||||||
export default class UserThreads extends Component {
|
export default class UserThreads extends Component {
|
||||||
@service chat;
|
@service chat;
|
||||||
@service chatApi;
|
@service chatApi;
|
||||||
@service router;
|
|
||||||
|
|
||||||
loadMore = modifier((element) => {
|
|
||||||
this.intersectionObserver = new IntersectionObserver(this.loadThreads);
|
|
||||||
this.intersectionObserver.observe(element);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
this.intersectionObserver.disconnect();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
fill = modifier((element) => {
|
|
||||||
this.resizeObserver = new ResizeObserver(() => {
|
|
||||||
if (isElementInViewport(element)) {
|
|
||||||
this.loadThreads();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.resizeObserver.observe(element);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
this.resizeObserver.disconnect();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
@cached
|
@cached
|
||||||
get threadsCollection() {
|
get threadsCollection() {
|
||||||
return this.chatApi.userThreads(this.handleLoadedThreads);
|
return this.chatApi.userThreads(this.handleLoadedThreads);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
|
||||||
loadThreads() {
|
|
||||||
discourseDebounce(this, this.debouncedLoadThreads, INPUT_DELAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
async debouncedLoadThreads() {
|
|
||||||
await this.threadsCollection.load({ limit: 10 });
|
|
||||||
}
|
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
handleLoadedThreads(result) {
|
handleLoadedThreads(result) {
|
||||||
return result.threads.map((threadObject) => {
|
return result.threads.map((threadObject) => {
|
||||||
@ -71,12 +33,15 @@ export default class UserThreads extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="c-user-threads" {{this.fill}}>
|
<List
|
||||||
{{#each this.threadsCollection.items as |thread|}}
|
@collection={{this.threadsCollection}}
|
||||||
|
class="c-user-threads"
|
||||||
|
as |list|
|
||||||
|
>
|
||||||
|
<list.Item as |thread|>
|
||||||
<div class="c-user-thread" data-id={{thread.id}}>
|
<div class="c-user-thread" data-id={{thread.id}}>
|
||||||
<ThreadTitle @thread={{thread}} />
|
<ThreadTitle @thread={{thread}} />
|
||||||
<ChannelTitle @channel={{thread.channel}} />
|
<ChannelTitle @channel={{thread.channel}} />
|
||||||
|
|
||||||
<ThreadIndicator
|
<ThreadIndicator
|
||||||
@message={{thread.originalMessage}}
|
@message={{thread.originalMessage}}
|
||||||
@interactiveUser={{false}}
|
@interactiveUser={{false}}
|
||||||
@ -84,16 +49,7 @@ export default class UserThreads extends Component {
|
|||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
</list.Item>
|
||||||
|
</List>
|
||||||
<div {{this.loadMore}}>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ConditionalLoadingSpinner
|
|
||||||
@condition={{this.threadsCollection.loading}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
}
|
}
|
||||||
|
@ -94,12 +94,16 @@ export default class ChatApi extends Service {
|
|||||||
*
|
*
|
||||||
* this.chatApi.channels.then(channels => { ... })
|
* this.chatApi.channels.then(channels => { ... })
|
||||||
*/
|
*/
|
||||||
channels() {
|
channels(params = {}) {
|
||||||
return new Collection(`${this.#basePath}/channels`, (response) => {
|
return new Collection(
|
||||||
|
`${this.#basePath}/channels`,
|
||||||
|
(response) => {
|
||||||
return response.channels.map((channel) =>
|
return response.channels.map((channel) =>
|
||||||
this.chatChannelsManager.store(channel)
|
this.chatChannelsManager.store(channel)
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
params
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
import Service, { inject as service } from "@ember/service";
|
import Service, { inject as service } from "@ember/service";
|
||||||
import ChatDrawerChannel from "discourse/plugins/chat/discourse/components/chat-drawer/channel";
|
import ChatDrawerRoutesChannel from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channel";
|
||||||
import ChatDrawerChannelThreads from "discourse/plugins/chat/discourse/components/chat-drawer/channel-threads";
|
import ChatDrawerRoutesChannelThread from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channel-thread";
|
||||||
import ChatDrawerIndex from "discourse/plugins/chat/discourse/components/chat-drawer/index";
|
import ChatDrawerRoutesChannelThreads from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channel-threads";
|
||||||
import ChatDrawerThread from "discourse/plugins/chat/discourse/components/chat-drawer/thread";
|
import ChatDrawerRoutesChannels from "discourse/plugins/chat/discourse/components/chat/drawer-routes/channels";
|
||||||
import ChatDrawerThreads from "discourse/plugins/chat/discourse/components/chat-drawer/threads";
|
import ChatDrawerRoutesThreads from "discourse/plugins/chat/discourse/components/chat/drawer-routes/threads";
|
||||||
|
|
||||||
const ROUTES = {
|
const ROUTES = {
|
||||||
"chat.channel": { name: ChatDrawerChannel },
|
"chat.channel": { name: ChatDrawerRoutesChannel },
|
||||||
"chat.channel.thread": {
|
"chat.channel.thread": {
|
||||||
name: ChatDrawerThread,
|
name: ChatDrawerRoutesChannelThread,
|
||||||
extractParams: (route) => {
|
extractParams: (route) => {
|
||||||
return {
|
return {
|
||||||
channelId: route.parent.params.channelId,
|
channelId: route.parent.params.channelId,
|
||||||
@ -18,7 +18,7 @@ const ROUTES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"chat.channel.thread.index": {
|
"chat.channel.thread.index": {
|
||||||
name: ChatDrawerThread,
|
name: ChatDrawerRoutesChannelThread,
|
||||||
extractParams: (route) => {
|
extractParams: (route) => {
|
||||||
return {
|
return {
|
||||||
channelId: route.parent.params.channelId,
|
channelId: route.parent.params.channelId,
|
||||||
@ -27,7 +27,7 @@ const ROUTES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"chat.channel.thread.near-message": {
|
"chat.channel.thread.near-message": {
|
||||||
name: ChatDrawerThread,
|
name: ChatDrawerRoutesChannelThread,
|
||||||
extractParams: (route) => {
|
extractParams: (route) => {
|
||||||
return {
|
return {
|
||||||
channelId: route.parent.parent.params.channelId,
|
channelId: route.parent.parent.params.channelId,
|
||||||
@ -37,7 +37,7 @@ const ROUTES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"chat.channel.threads": {
|
"chat.channel.threads": {
|
||||||
name: ChatDrawerChannelThreads,
|
name: ChatDrawerRoutesChannelThreads,
|
||||||
extractParams: (route) => {
|
extractParams: (route) => {
|
||||||
return {
|
return {
|
||||||
channelId: route.parent.params.channelId,
|
channelId: route.parent.params.channelId,
|
||||||
@ -45,11 +45,11 @@ const ROUTES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"chat.threads": {
|
"chat.threads": {
|
||||||
name: ChatDrawerThreads,
|
name: ChatDrawerRoutesThreads,
|
||||||
},
|
},
|
||||||
chat: { name: ChatDrawerIndex },
|
chat: { name: ChatDrawerRoutesChannels },
|
||||||
"chat.channel.near-message": {
|
"chat.channel.near-message": {
|
||||||
name: ChatDrawerChannel,
|
name: ChatDrawerRoutesChannel,
|
||||||
extractParams: (route) => {
|
extractParams: (route) => {
|
||||||
return {
|
return {
|
||||||
channelId: route.parent.params.channelId,
|
channelId: route.parent.params.channelId,
|
||||||
@ -58,7 +58,7 @@ const ROUTES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"chat.channel-legacy": {
|
"chat.channel-legacy": {
|
||||||
name: ChatDrawerChannel,
|
name: ChatDrawerRoutesChannel,
|
||||||
extractParams: (route) => {
|
extractParams: (route) => {
|
||||||
return {
|
return {
|
||||||
channelId: route.params.channelId,
|
channelId: route.params.channelId,
|
||||||
@ -83,7 +83,7 @@ export default class ChatDrawerRouter extends Service {
|
|||||||
|
|
||||||
this.drawerRoute = ROUTES[route.name];
|
this.drawerRoute = ROUTES[route.name];
|
||||||
this.params = this.drawerRoute?.extractParams?.(route) || route.params;
|
this.params = this.drawerRoute?.extractParams?.(route) || route.params;
|
||||||
this.component = this.drawerRoute?.name || ChatDrawerIndex;
|
this.component = this.drawerRoute?.name || ChatDrawerRoutesChannels;
|
||||||
|
|
||||||
this.drawerRoute.activate?.(route);
|
this.drawerRoute.activate?.(route);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
import { computed } from "@ember/object";
|
import { action, computed } from "@ember/object";
|
||||||
import { and } from "@ember/object/computed";
|
import { and } from "@ember/object/computed";
|
||||||
import { cancel, next } from "@ember/runloop";
|
import { cancel, next } from "@ember/runloop";
|
||||||
import Service, { inject as service } from "@ember/service";
|
import Service, { inject as service } from "@ember/service";
|
||||||
@ -414,4 +414,13 @@ export default class Chat extends Service {
|
|||||||
"Use the new chat API `api.registerChatComposerButton` instead of `chat.addToolbarButton`"
|
"Use the new chat API `api.registerChatComposerButton` instead of `chat.addToolbarButton`"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleDrawer() {
|
||||||
|
this.chatStateManager.didToggleDrawer();
|
||||||
|
this.appEvents.trigger(
|
||||||
|
"chat:toggle-expand",
|
||||||
|
this.chatStateManager.isDrawerExpanded
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
<ChatBrowseView @status="all" />
|
<Chat::Routes::Browse @status="all" />
|
@ -1 +1 @@
|
|||||||
<ChatBrowseView @status="archived" />
|
<Chat::Routes::Browse @status="archived" />
|
@ -1 +1 @@
|
|||||||
<ChatBrowseView @status="closed" />
|
<Chat::Routes::Browse @status="closed" />
|
@ -1 +1 @@
|
|||||||
<ChatBrowseView @status="open" />
|
<Chat::Routes::Browse @status="open" />
|
@ -1 +1 @@
|
|||||||
<ChatChannelMembers @channel={{this.model}} />
|
<Chat::Routes::ChannelInfoMembers @channel={{this.model}} />
|
@ -1 +1 @@
|
|||||||
<ChatChannelSettings @channel={{this.model}} />
|
<Chat::Routes::ChannelInfoSettings @channel={{this.model}} />
|
@ -1 +1 @@
|
|||||||
<ChatChannelInfo @channel={{this.model}} />
|
<Chat::Routes::ChannelInfo @channel={{this.model}} />
|
@ -1,7 +1,4 @@
|
|||||||
{{#each (array this.model) as |thread|}}
|
<Chat::Routes::ChannelThread
|
||||||
<ChatThread
|
@thread={{this.model}}
|
||||||
@thread={{thread}}
|
|
||||||
@targetMessageId={{this.targetMessageId}}
|
@targetMessageId={{this.targetMessageId}}
|
||||||
@includeHeader={{true}}
|
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
|
@ -1 +1 @@
|
|||||||
<ChatThreadList @channel={{this.model}} @includeHeader={{true}} />
|
<Chat::Routes::ChannelThreads @channel={{this.model}} />
|
@ -1,8 +1,4 @@
|
|||||||
<FullPageChat
|
<Chat::Routes::Channel
|
||||||
@channel={{this.model}}
|
@channel={{this.model}}
|
||||||
@targetMessageId={{this.targetMessageId}}
|
@targetMessageId={{this.targetMessageId}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ChatSidePanel>
|
|
||||||
{{outlet}}
|
|
||||||
</ChatSidePanel>
|
|
@ -1 +0,0 @@
|
|||||||
<ChatDraftChannelScreen />
|
|
@ -1 +1 @@
|
|||||||
<Chat::Threads />
|
<Chat::Routes::Threads />
|
@ -3,7 +3,7 @@
|
|||||||
--full-page-border-radius: 12px;
|
--full-page-border-radius: 12px;
|
||||||
--full-page-sidebar-width: 275px;
|
--full-page-sidebar-width: 275px;
|
||||||
--channel-list-avatar-size: 30px;
|
--channel-list-avatar-size: 30px;
|
||||||
--chat-header-offset: 50px;
|
--chat-header-offset: 46px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Very specific hack to ensure the contextual menu (copy/paste/...) is
|
// Very specific hack to ensure the contextual menu (copy/paste/...) is
|
||||||
@ -198,40 +198,9 @@ body.has-full-page-chat {
|
|||||||
grid-template-columns: var(--full-page-sidebar-width) 1fr;
|
grid-template-columns: var(--full-page-sidebar-width) 1fr;
|
||||||
background: var(--d-content-background);
|
background: var(--d-content-background);
|
||||||
|
|
||||||
.chat-full-page-header {
|
.c-navbar-container {
|
||||||
border-bottom: 1px solid var(--primary-low);
|
position: sticky;
|
||||||
background: var(--secondary);
|
top: var(--header-offset);
|
||||||
z-index: 3;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&__back-btn {
|
|
||||||
width: 40px;
|
|
||||||
min-width: 40px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-channel-title {
|
|
||||||
.category-chat-name,
|
|
||||||
.chat-name,
|
|
||||||
.dm-usernames {
|
|
||||||
color: var(--primary);
|
|
||||||
display: inline;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.-not-following {
|
|
||||||
.chat-channel-title {
|
|
||||||
max-width: calc(100% - 50px);
|
|
||||||
}
|
|
||||||
.join-channel-btn {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-messages-scroll {
|
.chat-messages-scroll {
|
||||||
@ -240,67 +209,6 @@ body.has-full-page-chat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-full-page-header__left-actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-full-page-header__title {
|
|
||||||
display: flex;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-full-page-header__right-actions {
|
|
||||||
align-items: stretch;
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 1;
|
|
||||||
gap: 0.5rem;
|
|
||||||
font-size: var(--font-up-1);
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-full-page-header {
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.chat-channel-header-details {
|
|
||||||
display: flex;
|
|
||||||
align-items: stretch;
|
|
||||||
flex: 1;
|
|
||||||
max-width: 100%;
|
|
||||||
|
|
||||||
.chat-channel-archive-status {
|
|
||||||
text-align: right;
|
|
||||||
padding-right: 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-channel-title {
|
|
||||||
margin: 0;
|
|
||||||
max-width: 100%;
|
|
||||||
|
|
||||||
.d-icon:not(.d-icon-lock) {
|
|
||||||
height: 1.25em;
|
|
||||||
width: 1.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-chat-name,
|
|
||||||
.dm-username {
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: var(--font-up-1);
|
|
||||||
line-height: var(--font-up-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dm-usernames {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.chat-channel-retry-archive {
|
|
||||||
display: flex;
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-preferences .chat-setting .controls {
|
.user-preferences .chat-setting .controls {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
|
||||||
.new-channel-btn {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__title {
|
&__title {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
.chat-channel-info {
|
.chat-channel-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
@ -1,10 +1,3 @@
|
|||||||
//appears in: header of chat pane, channel info, preview card
|
|
||||||
.chat-channel-title-wrapper {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-channel-title {
|
.chat-channel-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -7,6 +7,7 @@ body.composer-open .chat-drawer-outlet-container {
|
|||||||
top: -5px;
|
top: -5px;
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
|
z-index: z("composer", "content");
|
||||||
}
|
}
|
||||||
|
|
||||||
html:not(.rtl) {
|
html:not(.rtl) {
|
||||||
@ -30,36 +31,25 @@ html.rtl {
|
|||||||
right: var(--composer-right, 20px);
|
right: var(--composer-right, 20px);
|
||||||
left: 0;
|
left: 0;
|
||||||
max-height: calc(100% - var(--header-offset) - 15px);
|
max-height: calc(100% - var(--header-offset) - 15px);
|
||||||
|
|
||||||
.rtl & {
|
|
||||||
left: var(--composer-right, 20px);
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
||||||
> * {
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-channel-title {
|
|
||||||
font-weight: bold;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.composer-draft-collapsed {
|
|
||||||
bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-bottom: var(--composer-height, 0);
|
padding-bottom: var(--composer-height, 0);
|
||||||
transition: all 100ms ease-in;
|
transition: all 100ms ease-in;
|
||||||
transition-property: bottom, padding-bottom;
|
transition-property: bottom, padding-bottom;
|
||||||
|
|
||||||
|
.rtl & {
|
||||||
|
left: var(--composer-right, 20px);
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-drawer {
|
.chat-drawer {
|
||||||
@ -101,170 +91,11 @@ html.rtl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-drawer-header__left-actions {
|
|
||||||
display: flex;
|
|
||||||
height: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-drawer-header__right-actions {
|
|
||||||
display: flex;
|
|
||||||
height: 2rem;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-drawer-header__top-line {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-drawer-header__bottom-line {
|
|
||||||
height: 1.5rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-drawer-header__title {
|
|
||||||
@include ellipsis;
|
|
||||||
display: flex;
|
|
||||||
width: auto;
|
|
||||||
font-weight: 700;
|
|
||||||
padding: 0 0.5rem 0 0;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 2rem;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.chat-drawer-header__top-line {
|
|
||||||
padding: 0.25rem;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a.chat-drawer-header__title {
|
|
||||||
&:hover {
|
|
||||||
.chat-drawer-header__top-line {
|
|
||||||
background: var(--primary-low);
|
|
||||||
border-radius: var(--d-border-radius);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-drawer-header__icon {
|
|
||||||
margin-right: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-drawer-header__divider {
|
|
||||||
margin: 0 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-drawer-header {
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-bottom: solid 1px var(--primary-low);
|
|
||||||
border-radius: var(--d-border-radius-large) var(--d-border-radius-large) 0 0;
|
|
||||||
background: var(--primary-very-low);
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0.25rem;
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-channel-title {
|
|
||||||
font-weight: 700;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&__user-info {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-name,
|
|
||||||
.chat-drawer-name,
|
|
||||||
.category-chat-name,
|
|
||||||
.dm-usernames {
|
|
||||||
color: var(--primary);
|
|
||||||
}
|
|
||||||
.category-chat-badge,
|
|
||||||
.chat-drawer-badge {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
.d-icon:not(.d-icon-lock) {
|
|
||||||
width: 1.25em;
|
|
||||||
height: 1.25em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dm-usernames {
|
|
||||||
max-width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d-icon:not(.d-icon-d-chat) {
|
|
||||||
color: var(--primary-high);
|
|
||||||
}
|
|
||||||
.category-hashtag {
|
|
||||||
padding: 2px 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__close-btn,
|
|
||||||
&__back-btn,
|
|
||||||
&__full-screen-btn,
|
|
||||||
&__thread-list-btn,
|
|
||||||
&__expand-btn {
|
|
||||||
height: 30px;
|
|
||||||
width: 30px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 100%;
|
|
||||||
|
|
||||||
&:hover:active {
|
|
||||||
background: var(--primary-low);
|
|
||||||
}
|
|
||||||
|
|
||||||
.d-icon {
|
|
||||||
color: var(--primary-low-mid);
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:visited {
|
|
||||||
.d-icon {
|
|
||||||
color: var(--primary-low-mid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
background: none;
|
|
||||||
|
|
||||||
.d-icon {
|
|
||||||
background: none;
|
|
||||||
color: var(--primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.d-icon {
|
|
||||||
color: var(--primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__thread-list-btn.has-unreads {
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-drawer-content {
|
.chat-drawer-content {
|
||||||
@include chat-scrollbar();
|
@include chat-scrollbar();
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 1px;
|
min-height: 1px;
|
||||||
padding-bottom: 0.25em;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: contain;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
@mixin chat-height($inset: 0px) {
|
@mixin chat-height($inset: 0px) {
|
||||||
// desktop and mobile
|
// desktop and mobile
|
||||||
|
// 46px is the height of the navbar
|
||||||
height: calc(
|
height: calc(
|
||||||
var(--chat-vh, 1vh) * 100 - var(--header-offset, 0px) -
|
var(--chat-vh, 1vh) * 100 - var(--header-offset, 0px) -
|
||||||
var(--composer-height, 0px)
|
var(--composer-height, 0px) - var(--chat-header-offset)
|
||||||
);
|
);
|
||||||
|
|
||||||
// mobile with keyboard opened
|
// mobile with keyboard opened
|
||||||
|
@ -26,5 +26,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.full-page-chat .chat-mention-warnings {
|
.full-page-chat .chat-mention-warnings {
|
||||||
top: 4rem;
|
top: 2rem;
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,58 @@
|
|||||||
.chat-navbar {
|
.c-navbar {
|
||||||
flex-shrink: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
gap: 0.25rem;
|
||||||
|
|
||||||
&-container {
|
&-container {
|
||||||
padding-inline: 1rem;
|
padding-inline: 0.5rem;
|
||||||
position: sticky;
|
|
||||||
border-bottom: 1px solid var(--primary-low);
|
border-bottom: 1px solid var(--primary-low);
|
||||||
background: var(--secondary);
|
background: var(--secondary);
|
||||||
top: var(--header-offset);
|
height: var(--chat-header-offset);
|
||||||
height: 50px;
|
min-height: var(--chat-header-offset);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
z-index: z("header") - 1;
|
z-index: z("composer", "content") - 1;
|
||||||
|
|
||||||
|
&.-clickable {
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-navbar__right-actions {
|
.single-select-header {
|
||||||
|
padding: 0.3675rem 0.584rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-navbar__channel-title {
|
||||||
|
@include ellipsis();
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-navbar__title {
|
||||||
|
@include ellipsis();
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-navbar__sub-title {
|
||||||
|
line-height: var(--line-height-small);
|
||||||
|
font-size: var(--font-down-1-rem);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-navbar__threads-list-button {
|
||||||
|
gap: 0.25rem;
|
||||||
|
|
||||||
|
&.has-unreads {
|
||||||
|
.d-icon-discourse-threads {
|
||||||
|
color: var(--tertiary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-navbar__actions {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
@ -18,32 +18,25 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background: var(--tertiary-low);
|
background: var(--tertiary-low);
|
||||||
padding: 0.5em 0 0.5em 1em;
|
padding: 0.5rem;
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
padding: 0.5em 0 0.5em 1em;
|
|
||||||
min-width: 280px;
|
min-width: 280px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
gap: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dismiss-btn {
|
.dismiss-btn {
|
||||||
margin: 0 0.25em;
|
|
||||||
color: var(--primary-medium);
|
color: var(--primary-medium);
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
background-color: transparent;
|
background: var(--tertiary-medium);
|
||||||
.d-icon {
|
|
||||||
color: var(--primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.d-icon {
|
|
||||||
color: var(--primary-medium);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-page-chat .chat-notices {
|
.full-page-chat .chat-notices {
|
||||||
top: 4rem;
|
top: 2rem;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
.chat-side-panel-resizer {
|
.chat-side-panel-resizer {
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: z("composer", "content") - 1;
|
z-index: z("composer", "content") - 1;
|
||||||
transition: background-color 0.15s 0.15s;
|
transition: background-color 0.15s 0.15s;
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
@mixin chat-channel-header-button {
|
|
||||||
color: var(--primary-low-mid);
|
|
||||||
padding: 0.25em 0.4em;
|
|
||||||
|
|
||||||
.d-icon {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:visited {
|
|
||||||
color: var(--primary-low-mid);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--primary-medium);
|
|
||||||
background: var(--primary-very-low);
|
|
||||||
border-radius: var(--d-border-radius);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.d-icon {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-channel {
|
|
||||||
.chat-threads-list-button {
|
|
||||||
@include chat-channel-header-button;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&.has-unreads {
|
|
||||||
color: var(--tertiary-med-or-tertiary);
|
|
||||||
gap: 0.25rem;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--tertiary-hover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.d-icon {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.discourse-touch & {
|
|
||||||
background: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
.discourse-touch & {
|
|
||||||
background: var(--secondary-very-high) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.open-drawer-btn {
|
|
||||||
@include chat-channel-header-button;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +1,8 @@
|
|||||||
.chat-thread-header {
|
.chat-thread-header {
|
||||||
height: var(--chat-header-offset);
|
|
||||||
min-height: var(--chat-header-offset);
|
|
||||||
border-bottom: 1px solid var(--primary-low);
|
border-bottom: 1px solid var(--primary-low);
|
||||||
border-top: 1px solid var(--primary-low);
|
border-top: 1px solid var(--primary-low);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-inline: 0.5rem;
|
padding-inline: 0.5rem;
|
||||||
|
|
||||||
.touch & {
|
|
||||||
&__label {
|
|
||||||
font-size: var(--font-up-1-rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-thread__back-to-previous-route {
|
|
||||||
padding: 0.5rem 0;
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__buttons {
|
|
||||||
display: flex;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__left-buttons {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
.chat-thread-list-header {
|
.chat-thread-list-header {
|
||||||
height: var(--chat-header-offset);
|
|
||||||
min-height: var(--chat-header-offset);
|
|
||||||
border-bottom: 1px solid var(--primary-low);
|
border-bottom: 1px solid var(--primary-low);
|
||||||
border-top: 1px solid var(--primary-low);
|
border-top: 1px solid var(--primary-low);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
.full-page-chat-header {
|
|
||||||
display: flex;
|
|
||||||
padding: 0.25rem;
|
|
||||||
border-bottom: 1px solid var(--primary-low);
|
|
||||||
justify-content: space-between;
|
|
||||||
@include ellipsis;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.chat-channel-info-link {
|
|
||||||
justify-self: flex-end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-page-chat-header__about-link {
|
|
||||||
@include ellipsis;
|
|
||||||
padding-right: 0.25rem;
|
|
||||||
|
|
||||||
.chat-channel-title__name {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
.chat-channel-title {
|
|
||||||
padding: 0.5rem 0.5rem 0.25rem 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-page-chat-header__members-link {
|
|
||||||
padding: 0 0.5rem 0.5rem 0.5rem;
|
|
||||||
font-size: var(--font-down-1);
|
|
||||||
color: var(--primary-medium);
|
|
||||||
|
|
||||||
&:visited {
|
|
||||||
color: var(--primary-medium);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-page-chat-header__first-row {
|
|
||||||
display: flex;
|
|
||||||
height: 45px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-page-chat-header__second-row {
|
|
||||||
display: flex;
|
|
||||||
height: 32px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
@import "chat-unread-indicator";
|
@import "chat-unread-indicator";
|
||||||
@import "chat-height-mixin";
|
@import "chat-height-mixin";
|
||||||
@import "chat-thread-header-buttons";
|
|
||||||
@import "base-common";
|
@import "base-common";
|
||||||
@import "sidebar-extensions";
|
@import "sidebar-extensions";
|
||||||
@import "chat-browse";
|
@import "chat-browse";
|
||||||
@ -41,7 +40,6 @@
|
|||||||
@import "chat-transcript";
|
@import "chat-transcript";
|
||||||
@import "core-extensions";
|
@import "core-extensions";
|
||||||
@import "dc-filter-input";
|
@import "dc-filter-input";
|
||||||
@import "full-page-chat-header";
|
|
||||||
@import "incoming-chat-webhooks";
|
@import "incoming-chat-webhooks";
|
||||||
@import "reviewable-chat-message";
|
@import "reviewable-chat-message";
|
||||||
@import "chat-thread-list-item";
|
@import "chat-thread-list-item";
|
||||||
|
@ -12,13 +12,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-full-page-header {
|
|
||||||
padding: 0 1rem;
|
|
||||||
height: var(--chat-header-offset);
|
|
||||||
min-height: var(--chat-header-offset);
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-channel {
|
.chat-channel {
|
||||||
.chat-messages-container {
|
.chat-messages-container {
|
||||||
&.has-reply {
|
&.has-reply {
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
.chat-channel-title-wrapper {
|
|
||||||
padding: 0.25rem;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--primary-very-low);
|
|
||||||
border-radius: var(--d-border-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-channel-title {
|
|
||||||
&__user-info {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
@import "base-desktop";
|
@import "base-desktop";
|
||||||
@import "chat-channel-title";
|
|
||||||
@import "chat-composer-uploads";
|
@import "chat-composer-uploads";
|
||||||
@import "chat-index-drawer";
|
@import "chat-index-drawer";
|
||||||
@import "chat-index-full-page";
|
@import "chat-index-full-page";
|
||||||
|
@ -25,7 +25,7 @@ html.has-full-page-chat {
|
|||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-areas: "threads";
|
grid-template-areas: "threads";
|
||||||
|
|
||||||
.chat-channel {
|
.c-routes-channel {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,13 +54,6 @@ html.has-full-page-chat {
|
|||||||
.chat-drawer {
|
.chat-drawer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-full-page-header {
|
|
||||||
background-color: var(--secondary);
|
|
||||||
padding: 0 10px;
|
|
||||||
height: 50px;
|
|
||||||
min-height: 50px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-container .channels-list .chat-channel-divider {
|
.sidebar-container .channels-list .chat-channel-divider {
|
||||||
@ -77,18 +70,6 @@ html.has-full-page-chat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-full-page-header {
|
|
||||||
.chat-channel-header-details {
|
|
||||||
.chat-channel-retry-archive {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.chat-channel-archive-failed-retry {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-message-separator {
|
.chat-message-separator {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ RSpec.describe "Browse page", type: :system do
|
|||||||
context "when on mobile", mobile: true do
|
context "when on mobile", mobile: true do
|
||||||
it "has a back button" do
|
it "has a back button" do
|
||||||
chat_page.visit_browse
|
chat_page.visit_browse
|
||||||
find(".chat-full-page-header__back-btn").click
|
find(".c-navbar__back-button").click
|
||||||
|
|
||||||
expect(browse_page).to have_current_path("/chat")
|
expect(browse_page).to have_current_path("/chat")
|
||||||
end
|
end
|
||||||
@ -80,6 +80,7 @@ RSpec.describe "Browse page", type: :system do
|
|||||||
context "when results are found" do
|
context "when results are found" do
|
||||||
it "lists expected results" do
|
it "lists expected results" do
|
||||||
chat_page.visit_browse
|
chat_page.visit_browse
|
||||||
|
|
||||||
browse_page.search(category_channel_1.name)
|
browse_page.search(category_channel_1.name)
|
||||||
|
|
||||||
expect(browse_page).to have_channel(name: category_channel_1.name)
|
expect(browse_page).to have_channel(name: category_channel_1.name)
|
||||||
|
@ -18,7 +18,7 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||||||
it "redirects to browse page" do
|
it "redirects to browse page" do
|
||||||
chat_page.visit_browse
|
chat_page.visit_browse
|
||||||
find(".chat-channel-card__setting").click
|
find(".chat-channel-card__setting").click
|
||||||
find(".chat-full-page-header__back-btn").click
|
find(".c-navbar__back-button").click
|
||||||
|
|
||||||
expect(page).to have_current_path("/chat/browse/open")
|
expect(page).to have_current_path("/chat/browse/open")
|
||||||
end
|
end
|
||||||
@ -29,8 +29,8 @@ RSpec.describe "Channel - Info - Settings page", type: :system do
|
|||||||
context "when clicking back button" do
|
context "when clicking back button" do
|
||||||
it "redirects to channel page" do
|
it "redirects to channel page" do
|
||||||
chat_page.visit_channel(channel_1)
|
chat_page.visit_channel(channel_1)
|
||||||
find(".chat-channel-title-wrapper").click
|
find(".c-navbar__channel-title").click
|
||||||
find(".chat-full-page-header__back-btn").click
|
find(".c-navbar__back-button").click
|
||||||
|
|
||||||
expect(page).to have_current_path(chat.channel_path(channel_1.slug, channel_1.id))
|
expect(page).to have_current_path(chat.channel_path(channel_1.slug, channel_1.id))
|
||||||
end
|
end
|
||||||
|
@ -22,7 +22,7 @@ RSpec.describe "Drawer", type: :system do
|
|||||||
visit("/")
|
visit("/")
|
||||||
chat_page.open_from_header
|
chat_page.open_from_header
|
||||||
drawer_page.open_channel(channel)
|
drawer_page.open_channel(channel)
|
||||||
page.find(".chat-channel-title").click
|
page.find(".c-navbar__channel-title").click
|
||||||
|
|
||||||
expect(page).to have_current_path("/chat/c/#{channel.slug}/#{channel.id}/info/members")
|
expect(page).to have_current_path("/chat/c/#{channel.slug}/#{channel.id}/info/members")
|
||||||
end
|
end
|
||||||
@ -94,7 +94,7 @@ RSpec.describe "Drawer", type: :system do
|
|||||||
chat_page.open_from_header
|
chat_page.open_from_header
|
||||||
expect(page).to have_selector(".chat-drawer.is-expanded")
|
expect(page).to have_selector(".chat-drawer.is-expanded")
|
||||||
|
|
||||||
page.find(".chat-drawer-header").click
|
page.find(".c-navbar").click
|
||||||
|
|
||||||
expect(page).to have_selector(".chat-drawer:not(.is-expanded)")
|
expect(page).to have_selector(".chat-drawer:not(.is-expanded)")
|
||||||
end
|
end
|
||||||
|
@ -337,7 +337,7 @@ RSpec.describe "Navigation", type: :system do
|
|||||||
context "when going back to channel from channel settings in full page" do
|
context "when going back to channel from channel settings in full page" do
|
||||||
it "activates the channel in the sidebar" do
|
it "activates the channel in the sidebar" do
|
||||||
visit("/chat/c/#{category_channel.slug}/#{category_channel.id}/info/settings")
|
visit("/chat/c/#{category_channel.slug}/#{category_channel.id}/info/settings")
|
||||||
find(".chat-full-page-header__back-btn").click
|
find(".c-navbar__back-button").click
|
||||||
expect(page).to have_content(message.message)
|
expect(page).to have_content(message.message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -93,10 +93,10 @@ module PageObjects
|
|||||||
end
|
end
|
||||||
|
|
||||||
def minimize_full_page
|
def minimize_full_page
|
||||||
find(".open-drawer-btn").click
|
find(".c-navbar__open-drawer-button").click
|
||||||
end
|
end
|
||||||
|
|
||||||
NEW_CHANNEL_BUTTON_SELECTOR = ".new-channel-btn"
|
NEW_CHANNEL_BUTTON_SELECTOR = ".c-navbar__new-channel-button"
|
||||||
|
|
||||||
def new_channel_button
|
def new_channel_button
|
||||||
find(NEW_CHANNEL_BUTTON_SELECTOR)
|
find(NEW_CHANNEL_BUTTON_SELECTOR)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user