diff --git a/src/plugins/sib-action-buttons-inline.js b/src/plugins/sib-action-buttons-inline.js new file mode 100644 index 0000000000000000000000000000000000000000..77252f6de816ce3a7fa727f6e5a8803523f0bfa1 --- /dev/null +++ b/src/plugins/sib-action-buttons-inline.js @@ -0,0 +1,39 @@ +/** + * Render the action buttons off the drawer. + * The buttons should be shown on message hover, on the right side of the message. + */ +converse.plugins.add('sib-action-buttons-inline', { + initialize() { + const { html } = converse.env; + const _converse = this._converse; + const { api } = _converse; + + const MessageActions = api.elements.registry['converse-message-actions']; + + function getInlineActionsItem(o) { + return html` + <button class='chat-msg__action ${o.button_class}' @click='${o.handler}' title='${o.i18n_text}'> + <converse-icon class='${o.icon_class}' + path-prefix='${api.settings.get('assets_path')}' + color='var(--text-color-lighten-15-percent)' + size='1em'></converse-icon> + </button> + `; + } + + Object.assign(MessageActions.prototype, { + async renderActions() { + const buttons = await this.getActionButtons(); + const items = buttons.map(b => getInlineActionsItem(b)); + + if (items.length) { + return html` + <div class='chat-msg__actions chat-msg__actions--inline'>${items}</div> + `; + } else { + return ''; + } + }, + }); + }, +}); diff --git a/src/plugins/sib-emoji-picker.js b/src/plugins/sib-emoji-picker.js new file mode 100644 index 0000000000000000000000000000000000000000..fc4ed60e8a8b1f9890c5616e1eb2e572d55768dc --- /dev/null +++ b/src/plugins/sib-emoji-picker.js @@ -0,0 +1,82 @@ +import { Picker } from 'https://cdn.skypack.dev/emoji-picker-element'; + +/** + * Custom emoji picker. + * Replaces the default drawer with a custom component. + */ +converse.plugins.add('sib-emoji-picker', { + dependencies: [ + 'converse-emoji', + ], + initialize() { + const { html } = converse.env; + const _converse = this._converse; + const { api, __ } = _converse; + + // Register the picker element + api.elements.define('emoji-picker', Picker); + api.elements.register(); + + /** + * Force rendering of the emoji picker inside the dropdown. + * Note: Without this mixin, the IndexedDB can't be loaded for some reason. + */ + const EmojiDropdownMixin = { + render() { + return html` + <div class="dropup"> + <button class="toggle-emojis" + title="${__('Insert emojis')}" + data-toggle="dropdown" + aria-haspopup="true" + aria-expanded="false"> + <converse-icon class="fa fa-smile" + path-prefix="${api.settings.get('assets_path')}" + size="1em"></converse-icon> + </button> + <div class="dropdown-menu"> + <converse-emoji-picker .chatview="${this.chatview}" + .model="${this.model}" + ></converse-emoji-picker> + </div> + </div>`; + }, + async showMenu() { + await _showMenu.apply(this, arguments); + setTimeout(() => { + // Focus the search input afterwards + const picker = this.querySelector('emoji-picker'); + picker?.shadowRoot?.querySelector('.search')?.focus(); + }); + }, + }; + + // Apply mixin + const EmojiDropdown = api.elements.registry['converse-emoji-dropdown']; + const _showMenu = EmojiDropdown.prototype.showMenu; + Object.assign(EmojiDropdown.prototype, EmojiDropdownMixin); + + /** + * Update the emoji picker rendered content. + * with the new element. + */ + const EmojiPickerMixin = { + firstUpdated() { + }, + registerEvents() { + }, + render() { + return html` + <emoji-picker .chatview="${this.chatview}" + .model="${this.model}" + @emoji-click="${ev => this.insertIntoTextArea(ev.detail.unicode)}" + class="light" + ></emoji-picker>`; + }, + }; + + // Apply mixin + const EmojiPicker = api.elements.registry['converse-emoji-picker']; + Object.assign(EmojiPicker.prototype, EmojiPickerMixin); + }, +}); diff --git a/src/solid-xmpp-chat.js b/src/solid-xmpp-chat.js index 4223762587517dc40d7eb78748a3ae5921b10543..cfb903488ace9d1df0f418f2b9881816e647daab 100644 --- a/src/solid-xmpp-chat.js +++ b/src/solid-xmpp-chat.js @@ -6,9 +6,11 @@ import './conversejs/converse.min.js'; import './conversejs/emojis.js'; import './plugins/converse-rai.js'; +import './plugins/sib-action-buttons-inline.js'; import './plugins/sib-chat-navigation.js'; import './plugins/sib-custom-hats.js'; import './plugins/sib-disconnected.js'; +import './plugins/sib-emoji-picker.js'; import './plugins/sib-history-improved.js'; import './plugins/sib-mention-mobile.js'; import './plugins/sib-remove-notifications.js'; @@ -228,10 +230,12 @@ export const SolidXMPPChat = { }, 'whitelisted_plugins': [ 'converse-rai', + 'sib-action-buttons-inline', 'sib-chat-navigation', 'sib-connected', 'sib-custom-hats', 'sib-disconnected', + 'sib-emoji-picker', 'sib-history-improved', 'sib-mention-mobile', 'sib-remove-notifications', diff --git a/src/styles/index.scss b/src/styles/index.scss index f32781c268b36a7453acd6f20fb5d88c431f4f46..a1259b8ca851625d7e2708210338d3f33f8e598c 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -117,22 +117,22 @@ } /* Background when an emoji is hover*/ - .chatbox converse-emoji-picker { - - .emoji-picker__header ul li.emoji-category:hover, - .emoji-picker li.insert-emoji a:hover { - background: var(--chat-head-color); - } - } + //.chatbox converse-emoji-picker { + // + // .emoji-picker__header ul li.emoji-category:hover, + // .emoji-picker li.insert-emoji a:hover { + // background: var(--chat-head-color); + // } + //} /* underline underneath emoji in the emoji picker removed */ - .chatbox converse-emoji-picker { - - .emoji-picker__header ul li.emoji-category a, - .emoji-picker li.insert-emoji a { - text-decoration: none; - } - } + //.chatbox converse-emoji-picker { + // + // .emoji-picker__header ul li.emoji-category a, + // .emoji-picker li.insert-emoji a { + // text-decoration: none; + // } + //} /* Outline when the emoji button is selected */ .chatbox converse-chat-toolbar button:focus { @@ -140,10 +140,10 @@ } /* Modal when the connection is lost*/ - #alert-modal>.modal-dialog>.modal-content { + #alert-modal > .modal-dialog > .modal-content { top: 47px; - >div.modal-body>p { + > div.modal-body > p { color: var(--color-chat-grey-1); } } @@ -154,7 +154,7 @@ } /* To hide the trash icon because you can't remove a message for now */ - >.converse-chatboxes .chat-body .chat-msg__actions>button.chat-msg__action.fa-trash-alt { + > .converse-chatboxes .chat-body .chat-msg__actions > button.chat-msg__action.fa-trash-alt { display: none; } @@ -571,7 +571,7 @@ } .suggestion-box .suggestion-box__results, - .suggestion-box>ul { + .suggestion-box > ul { box-shadow: 0 0 5px 0 rgba(133, 140, 148, 0.09); } @@ -598,7 +598,7 @@ converse-chat-toolbar .far:hover svg, converse-chat-toolbar .fas svg, converse-chat-toolbar .fas:hover svg { - fill: var(--color-secondary)!important; + fill: var(--color-secondary) !important; } .chatroom .toggle-smiley .emoji-picker.toolbar-menu .emoji-picker__container .emoji-skintone-picker, @@ -607,14 +607,20 @@ } &.converse-fullscreen converse-emoji-dropdown .dropdown-menu { - min-width: 80vw; + min-width: unset; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + border-radius: 3px; } - @media (min-width: 600px) { - &.converse-fullscreen converse-emoji-dropdown .dropdown-menu { - min-width: 25vw; - } - } + //&.converse-fullscreen converse-emoji-dropdown .dropdown-menu { + // min-width: 80vw; + //} + // + //@media (min-width: 600px) { + // &.converse-fullscreen converse-emoji-dropdown .dropdown-menu { + // min-width: 25vw; + // } + //} &.converse-fullscreen .chatroom .sendXMPPMessage .chat-toolbar .fa, &.converse-fullscreen .chatroom .sendXMPPMessage .chat-toolbar .fa:hover, @@ -821,7 +827,7 @@ background: var(--hd-hightlight-color); } - .suggestion-box>ul>li[aria-selected=true] { + .suggestion-box > ul > li[aria-selected=true] { background: transparent; color: var(--chat-suggestion-selected-true) !important; } @@ -871,4 +877,32 @@ .converse-chatboxes .chatbox .box-flyout { width: 100% !important; } + + // + // Message Actions (inline) + // --------------------------------- + + .chat-msg { + position: relative; + } + + // Reset these positions + .chat-msg__content, .chat-msg__body, converse-message-actions { + position: initial; + } + + .chat-msg:not(:hover) .chat-msg__actions--inline { + display: none; + } + + .chat-msg__actions--inline { + display: flex; + position: absolute; + top: 0; + right: 0; + transform: translateY(-50%); + background: #f6f6f6; + border: 2px solid white; + border-radius: 3px; + } } \ No newline at end of file