Create the converse-avatar custom element

This commit is contained in:
JC Brand 2021-11-19 09:44:44 +01:00
parent e347621dc8
commit a5b73f0309
13 changed files with 107 additions and 89 deletions

View File

@ -1,4 +1,4 @@
import avatar from 'shared/templates/avatar.js';
import avatar from 'shared/avatar/templates/avatar.js';
import { __ } from 'i18n';
import { html } from 'lit';
import { modal_close_button, modal_header_close_button } from 'plugins/modal/templates/buttons.js'

View File

@ -6,7 +6,6 @@
import './view.js';
import '@converse/headless/plugins/chatboxes/index.js';
import ChatBoxViews from './container.js';
import { ViewWithAvatar } from 'shared/avatar.js';
import { _converse, api, converse } from '@converse/headless/core';
import { calculateViewportHeightUnit } from './utils.js';
@ -28,7 +27,6 @@ converse.plugins.add('converse-chatboxviews', {
'theme': 'default'
});
_converse.ViewWithAvatar = ViewWithAvatar;
_converse.chatboxviews = new ChatBoxViews();
/************************ BEGIN Event Handlers ************************/

View File

@ -1,54 +1,21 @@
import UserSettingsModal from 'modals/user-settings';
import tpl_profile from './templates/profile.js';
import { ElementViewWithAvatar } from 'shared/avatar.js';
import { CustomElement } from 'shared/components/element.js';
import { __ } from 'i18n';
import { _converse, api } from '@converse/headless/core';
import { render } from 'lit';
function getPrettyStatus (stat) {
if (stat === 'chat') {
return __('online');
} else if (stat === 'dnd') {
return __('busy');
} else if (stat === 'xa') {
return __('away for long');
} else if (stat === 'away') {
return __('away');
} else if (stat === 'offline') {
return __('offline');
} else {
return __(stat) || __('online');
}
}
class ProfileView extends ElementViewWithAvatar {
class ProfileView extends CustomElement {
async initialize () {
this.model = _converse.xmppstatus;
this.listenTo(this.model, "change", this.render);
this.listenTo(this.model, "change", this.requestUpdate);
await api.waitUntil('VCardsInitialized');
this.listenTo(this.model.vcard, "change", this.render);
this.render();
this.listenTo(this.model.vcard, "change", this.requestUpdate);
this.requestUpdate();
}
render () {
const chat_status = this.model.get('status') || 'offline';
render(tpl_profile(Object.assign(
this.model.toJSON(),
this.model.vcard.toJSON(), {
chat_status,
'fullname': this.model.vcard.get('fullname') || _converse.bare_jid,
"showUserSettingsModal": ev => this.showUserSettingsModal(ev),
'status_message': this.model.get('status_message') ||
__("I am %1$s", getPrettyStatus(chat_status)),
'logout': this.logout,
'showStatusChangeModal': () => this.showStatusChangeModal(),
'showProfileModal': () => this.showProfileModal()
})), this);
this.renderAvatar();
return tpl_profile(this);
}
showProfileModal (ev) {

View File

@ -1,5 +1,7 @@
import 'shared/avatar/avatar.js';
import { __ } from 'i18n';
import { api } from "@converse/headless/core";
import { _converse, api } from "@converse/headless/core";
import { getPrettyStatus } from '../utils.js';
import { html } from "lit";
@ -17,15 +19,18 @@ function tpl_user_settings_button (o) {
</a>`;
}
export default (o) => {
export default (el) => {
const chat_status = el.model.get('status') || 'offline';
const fullname = el.model.vcard?.get('fullname') || _converse.bare_jid;
const status_message = el.model.get('status_message') || __("I am %1$s", getPrettyStatus(chat_status));
const i18n_change_status = __('Click to change your chat status');
const show_settings_button = api.settings.get('show_client_info') || api.settings.get('allow_adhoc_commands');
let classes, color;
if (o.chat_status === 'online') {
if (chat_status === 'online') {
[classes, color] = ['fa fa-circle chat-status', 'chat-status-online'];
} else if (o.chat_status === 'dnd') {
} else if (chat_status === 'dnd') {
[classes, color] = ['fa fa-minus-circle chat-status', 'chat-status-busy'];
} else if (o.chat_status === 'away') {
} else if (chat_status === 'away') {
[classes, color] = ['fa fa-circle chat-status', 'chat-status-away'];
} else {
[classes, color] = ['fa fa-circle chat-status', 'subdued-color'];
@ -33,17 +38,17 @@ export default (o) => {
return html`
<div class="userinfo controlbox-padded">
<div class="controlbox-section profile d-flex">
<a class="show-profile" href="#" @click=${o.showProfileModal}>
<canvas class="avatar align-self-center" height="40" width="40"></canvas>
<a class="show-profile" href="#" @click=${el.showProfileModal}>
<converse-avatar class="avatar align-self-center" .model=${el.model.vcard} height="40" width="40"></converse-avatar>
</a>
<span class="username w-100 align-self-center">${o.fullname}</span>
${show_settings_button ? tpl_user_settings_button(o) : ''}
${api.settings.get('allow_logout') ? tpl_signout(o) : ''}
<span class="username w-100 align-self-center">${fullname}</span>
${show_settings_button ? tpl_user_settings_button(el) : ''}
${api.settings.get('allow_logout') ? tpl_signout(el) : ''}
</div>
<div class="d-flex xmpp-status">
<a class="change-status" title="${i18n_change_status}" data-toggle="modal" data-target="#changeStatusModal" @click=${o.showStatusChangeModal}>
<span class="${o.chat_status} w-100 align-self-center" data-value="${o.chat_status}">
<converse-icon color="var(--${color})" size="1em" class="${classes}"></converse-icon> ${o.status_message}</span>
<a class="change-status" title="${i18n_change_status}" data-toggle="modal" data-target="#changeStatusModal" @click=${el.showStatusChangeModal}>
<span class="${chat_status} w-100 align-self-center" data-value="${chat_status}">
<converse-icon color="var(--${color})" size="1em" class="${classes}"></converse-icon> ${status_message}</span>
</a>
</div>
</div>`

View File

@ -0,0 +1,17 @@
import { __ } from 'i18n';
export function getPrettyStatus (stat) {
if (stat === 'chat') {
return __('online');
} else if (stat === 'dnd') {
return __('busy');
} else if (stat === 'xa') {
return __('away for long');
} else if (stat === 'away') {
return __('away');
} else if (stat === 'offline') {
return __('offline');
} else {
return __(stat) || __('online');
}
}

View File

@ -0,0 +1,33 @@
import { CustomElement } from 'shared/components/element.js';
import tpl_avatar from './templates/avatar.js';
import { api } from '@converse/headless/core';
export default class Avatar extends CustomElement {
static get properties () {
return {
model: { type: Object },
width: { type: String },
height: { type: String },
}
}
constructor () {
super();
this.width = 36;
this.height = 36;
}
render () {
return tpl_avatar({
'classes': this.getAttribute('class'),
'width': this.width,
'height': this.height,
'image_type': this.model?.get('image_type'),
'image': this.model?.get('image')
});
}
}
api.elements.define('converse-avatar', Avatar);

View File

@ -2,10 +2,10 @@ import './message-actions.js';
import './message-body.js';
import 'shared/components/dropdown.js';
import 'shared/registry';
import tpl_file_progress from './templates/file-progress.js';
import MessageVersionsModal from 'modals/message-versions.js';
import OccupantModal from 'modals/occupant.js';
import UserDetailsModal from 'modals/user-details.js';
import filesize from 'filesize';
import log from '@converse/headless/log';
import tpl_info_message from './templates/info-message.js';
import tpl_mep_message from 'plugins/muc-views/templates/mep-message.js';
@ -18,8 +18,6 @@ import { __ } from 'i18n';
import { _converse, api, converse } from '@converse/headless/core';
import { getAppSettings } from '@converse/headless/shared/settings/utils.js';
import { getHats } from './utils.js';
import { html } from 'lit';
import { renderAvatar } from 'shared/directives/avatar';
const { Strophe, dayjs } = converse.env;
@ -116,17 +114,7 @@ export default class Message extends CustomElement {
// Can happen when file upload failed and page was reloaded
return '';
}
const i18n_uploading = __('Uploading file:');
const filename = this.model.file.name;
const size = filesize(this.model.file.size);
return html`
<div class="message chat-msg">
${ renderAvatar(this.getAvatarData()) }
<div class="chat-msg__content">
<span class="chat-msg__text">${i18n_uploading} <strong>${filename}</strong>, ${size}</span>
<progress value="${this.model.get('progress')}"/>
</div>
</div>`;
return tpl_file_progress(this);
}
renderChatMessage () {

View File

@ -0,0 +1,24 @@
import 'shared/avatar/avatar.js';
import filesize from 'filesize';
import { __ } from 'i18n';
import { html } from 'lit';
export default (el) => {
const i18n_uploading = __('Uploading file:');
const filename = el.model.file.name;
const size = filesize(el.model.file.size);
return html`
<div class="message chat-msg">
<converse-avatar class="avatar align-self-center" .model=${el.model.vcard} height="40" width="40"></converse-avatar>
${ el.shouldShowAvatar() ?
html`<a class="show-msg-author-modal" @click=${el.showUserModal}>
<converse-avatar class="avatar align-self-center" .model=${el.model.vcard} height="40" width="40"></converse-avatar>
</a>` : '' }
<div class="chat-msg__content">
<span class="chat-msg__text">${i18n_uploading} <strong>${filename}</strong>, ${size}</span>
<progress value="${el.model.get('progress')}"/>
</div>
</div>`;
}

View File

@ -1,7 +1,6 @@
import 'shared/chat/unfurl.js';
import { __ } from 'i18n';
import { html } from "lit";
import { renderAvatar } from 'shared/directives/avatar';
import { shouldRenderMediaFromURL } from '@converse/headless/utils/url.js';
@ -18,7 +17,11 @@ export default (el, o) => {
<!-- Anchor to allow us to scroll the message into view -->
<a id="${o.msgid}"></a>
<a class="show-msg-author-modal" @click=${el.showUserModal}>${ o.should_show_avatar ? renderAvatar(el.getAvatarData()) : '' }</a>
${ o.should_show_avatar ?
html`<a class="show-msg-author-modal" @click=${el.showUserModal}>
<converse-avatar class="avatar align-self-center" .model=${el.model.vcard} height="40" width="40"></converse-avatar>
</a>` : '' }
<div class="chat-msg__content chat-msg__content--${o.sender} ${o.is_me_message ? 'chat-msg__content--action' : ''}">
${ !o.is_me_message ? html`

View File

@ -1,4 +1,4 @@
import tpl_avatar from 'shared/templates/avatar.js';
import tpl_avatar from 'shared/avatar/templates/avatar.js';
import { Directive, directive } from "lit/directive.js";

View File

@ -1,17 +0,0 @@
import { __ } from '../i18n';
import { html } from "lit";
import { renderAvatar } from './../templates/directives/avatar';
export default (o) => {
const i18n_uploading = __('Uploading file:')
return html`
<div class="message chat-msg" data-isodate="${o.time}" data-msgid="${o.msgid}">
${ renderAvatar(this) }
<div class="chat-msg__content">
<span class="chat-msg__text">${i18n_uploading} <strong>${o.filename}</strong>, ${o.filesize}</span>
<progress value="${o.progress}"/>
</div>
</div>
`;
}