Browse Source

Added custom image modal + continued styling fix

q-apps
Justin Ferrari 2 years ago
parent
commit
73e4129d06
  1. 16
      qortal-ui-core/font/switch-theme.css
  2. 16
      qortal-ui-core/src/styles/switch-theme.css
  3. 4
      qortal-ui-plugins/plugins/core/components/ChatHead.js
  4. 270
      qortal-ui-plugins/plugins/core/components/ChatPage.js
  5. 38
      qortal-ui-plugins/plugins/core/components/ChatScroller-css.js
  6. 7
      qortal-ui-plugins/plugins/core/components/ChatScroller.js
  7. 246
      qortal-ui-plugins/plugins/core/components/ChatTextEditor.js
  8. 55
      qortal-ui-plugins/plugins/core/components/WrapperModal-css.js
  9. 27
      qortal-ui-plugins/plugins/core/components/WrapperModal.js

16
qortal-ui-core/font/switch-theme.css

@ -7,9 +7,17 @@ html {
--border: #d0d6de; --border: #d0d6de;
--border2: #dde2e8; --border2: #dde2e8;
--copybutton: #707584; --copybutton: #707584;
--chat-group: #080808;
--chat-bubble: #9f9f9f0a; --chat-bubble: #9f9f9f0a;
--chat-bubble-bg: #f3f3f3; --chat-bubble-bg: #f3f3f3;
--chat-bubble-msg-color: #080808; --chat-bubble-msg-color: #080808;
--reaction-bubble-outline: #6b6969;
--chat-menu-bg: #ffffff;
--chat-menu-outline: #dad9d9;
--chat-menu-icon: #3b3b3c;
--chat-menu-icon-hover: #dad9d9;
--block-user-bg-hover: #dad9d9;
--paperclip-icon: #494949;
--sectxt: #576374; --sectxt: #576374;
--vdicon: #707b8a; --vdicon: #707b8a;
--tradehead: #6a6c75; --tradehead: #6a6c75;
@ -46,9 +54,17 @@ html[theme="dark"] {
--border: #0b305e; --border: #0b305e;
--border2: #0b305e; --border2: #0b305e;
--copybutton: #d0d6de; --copybutton: #d0d6de;
--chat-group: #ffffff;
--chat-bubble: #9694941a; --chat-bubble: #9694941a;
--chat-bubble-bg: #2d3749; --chat-bubble-bg: #2d3749;
--chat-bubble-msg-color: #ffffff; --chat-bubble-msg-color: #ffffff;
--reaction-bubble-outline: #ffffff;
--chat-menu-bg: #32394c;
--chat-menu-outline: #32394c;
--chat-menu-icon: #ffffff;
--chat-menu-icon-hover: #a49a9a36;
--block-user-bg-hover: #121a2f;
--paperclip-icon: #d0c9c9;
--sectxt: #bbc3cd; --sectxt: #bbc3cd;
--vdicon: #d0d6de; --vdicon: #d0d6de;
--tradehead: #008fd5; --tradehead: #008fd5;

16
qortal-ui-core/src/styles/switch-theme.css

@ -7,9 +7,17 @@ html {
--border: #d0d6de; --border: #d0d6de;
--border2: #dde2e8; --border2: #dde2e8;
--copybutton: #707584; --copybutton: #707584;
--chat-group: #080808;
--chat-bubble: #9f9f9f0a; --chat-bubble: #9f9f9f0a;
--chat-bubble-bg: #f3f3f3; --chat-bubble-bg: #f3f3f3;
--chat-bubble-msg-color: #080808; --chat-bubble-msg-color: #080808;
--reaction-bubble-outline: #6b6969;
--chat-menu-bg: #ffffff;
--chat-menu-outline: #dad9d9;
--chat-menu-icon: #3b3b3c;
--chat-menu-icon-hover: #dad9d9;
--block-user-bg-hover: #dad9d9;
--paperclip-icon: #494949;
--sectxt: #576374; --sectxt: #576374;
--vdicon: #707b8a; --vdicon: #707b8a;
--tradehead: #6a6c75; --tradehead: #6a6c75;
@ -45,9 +53,17 @@ html[theme="dark"] {
--border: #0b305e; --border: #0b305e;
--border2: #0b305e; --border2: #0b305e;
--copybutton: #d0d6de; --copybutton: #d0d6de;
--chat-group: #ffffff;
--chat-bubble: #9694941a; --chat-bubble: #9694941a;
--chat-bubble-bg: #2d3749; --chat-bubble-bg: #2d3749;
--chat-bubble-msg-color: #ffffff; --chat-bubble-msg-color: #ffffff;
--reaction-bubble-outline: #ffffff;
--chat-menu-bg: #32394c;
--chat-menu-outline: #32394c;
--chat-menu-icon: #ffffff;
--chat-menu-icon-hover: #a49a9a36;
--block-user-bg-hover: #121a2f;
--paperclip-icon: #d0c9c9;
--sectxt: #bbc3cd; --sectxt: #bbc3cd;
--vdicon: #d0d6de; --vdicon: #d0d6de;
--tradehead: #008fd5; --tradehead: #008fd5;

4
qortal-ui-plugins/plugins/core/components/ChatHead.js

@ -36,7 +36,7 @@ class ChatHead extends LitElement {
.img-icon { .img-icon {
float: left; float: left;
font-size:40px; font-size:40px;
color: var(--black); color: var(--chat-group);
} }
.about { .about {
@ -82,7 +82,7 @@ class ChatHead extends LitElement {
<li @click=${() => this.getUrl(this.chatInfo.url)} class="clearfix ${this.activeChatHeadUrl === this.chatInfo.url ? 'active' : ''}"> <li @click=${() => this.getUrl(this.chatInfo.url)} class="clearfix ${this.activeChatHeadUrl === this.chatInfo.url ? 'active' : ''}">
<mwc-icon class="img-icon">account_circle</mwc-icon> <mwc-icon class="img-icon">account_circle</mwc-icon>
<div class="about"> <div class="about">
<div class="name"><span style="float:left; padding-left: 8px; color: var(--black);">${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)} </span> <mwc-icon style="float:right; padding: 0 1rem; color: var(--black);">${this.chatInfo.groupId !== undefined ? 'lock_open' : 'lock'}</mwc-icon> </div> <div class="name"><span style="float:left; padding-left: 8px; color: var(--chat-group);">${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)} </span> <mwc-icon style="float:right; padding: 0 1rem; color: var(--chat-group);">${this.chatInfo.groupId !== undefined ? 'lock_open' : 'lock'}</mwc-icon> </div>
</div> </div>
</li> </li>
` `

270
qortal-ui-plugins/plugins/core/components/ChatPage.js

@ -1,24 +1,25 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit';
import { render } from 'lit/html.js' import { render } from 'lit/html.js';
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js';
import { use, get, translate, registerTranslateConfig } from 'lit-translate' import { use, get, translate, registerTranslateConfig } from 'lit-translate';
import localForage from "localforage"; import localForage from "localforage";
registerTranslateConfig({ registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json()) loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
}) });
import ShortUniqueId from 'short-unique-id'; import ShortUniqueId from 'short-unique-id';
import Compressor from 'compressorjs'; import Compressor from 'compressorjs';
import { escape, unescape } from 'html-escaper'; import { escape, unescape } from 'html-escaper';
import { inputKeyCodes } from '../../utils/keyCodes.js' import { inputKeyCodes } from '../../utils/keyCodes.js';
import './ChatScroller.js' import './ChatScroller.js';
import './LevelFounder.js' import './LevelFounder.js';
import './NameMenu.js' import './NameMenu.js';
import './TimeAgo.js' import './TimeAgo.js';
import './ChatTextEditor' import './ChatTextEditor';
import '@polymer/paper-spinner/paper-spinner-lite.js' import './WrapperModal';
import '@material/mwc-button' import '@polymer/paper-spinner/paper-spinner-lite.js';
import '@material/mwc-dialog' import '@material/mwc-button';
import '@material/mwc-icon' import '@material/mwc-dialog';
import '@material/mwc-icon';
import { replaceMessagesEdited } from '../../utils/replace-messages-edited.js'; import { replaceMessagesEdited } from '../../utils/replace-messages-edited.js';
import { publishData } from '../../utils/publish-image.js'; import { publishData } from '../../utils/publish-image.js';
import WebWorker from 'web-worker:./computePowWorker.js'; import WebWorker from 'web-worker:./computePowWorker.js';
@ -61,21 +62,14 @@ class ChatPage extends LitElement {
chatMessageSize: { type: Number}, chatMessageSize: { type: Number},
imageFile: { type: Object }, imageFile: { type: Object },
isUploadingImage: { type: Boolean }, isUploadingImage: { type: Boolean },
caption: { type: String },
chatEditor: { type: Object }, chatEditor: { type: Object },
chatEditorNewChat: { type: Object } chatEditorNewChat: { type: Object },
userLanguage: { type: String },
} }
} }
static get styles() { static get styles() {
return css` return css`
* {
/* Styling mdc dialog native props */
--mdc-dialog-min-width: 300px;
--mdc-dialog-box-shadow:rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 2px 6px 2px;
--mdc-dialog-z-index: 5
}
html { html {
scroll-behavior: smooth; scroll-behavior: smooth;
} }
@ -100,10 +94,9 @@ class ChatPage extends LitElement {
width: 98%; width: 98%;
box-sizing: border-box; box-sizing: border-box;
margin-bottom: 8px; margin-bottom: 8px;
border: 1px solid var(--black); border: 1px solid var(--chat-bubble-bg);
border-radius: 10px; border-radius: 10px;
background: #f1f1f1; background: var(--chat-bubble-bg);
color: var(--black);
} }
.chat-text-area .typing-area textarea { .chat-text-area .typing-area textarea {
@ -425,10 +418,6 @@ class ChatPage extends LitElement {
} }
} }
.mdc-dialog .mdc-dialog__surface {
border-radius: 10px;
}
/* Add Image Modal Dialog Styling */ /* Add Image Modal Dialog Styling */
.dialog-container { .dialog-container {
@ -452,7 +441,9 @@ class ChatPage extends LitElement {
.dialog-image { .dialog-image {
width: 100%; width: 100%;
max-height: 300px;
border-radius: 0; border-radius: 0;
object-fit: contain;
} }
.red { .red {
@ -486,7 +477,7 @@ class ChatPage extends LitElement {
this.isLoading = false this.isLoading = false
this.isUserDown = false this.isUserDown = false
this.isPasteMenuOpen = false this.isPasteMenuOpen = false
this.chatEditorPlaceholder = this.renderPlaceholder() this.chatEditorPlaceholder = ""
this.messagesRendered = [] this.messagesRendered = []
this.repliedToMessageObj = null this.repliedToMessageObj = null
this.editedMessageObj = null this.editedMessageObj = null
@ -494,10 +485,13 @@ class ChatPage extends LitElement {
this.chatMessageSize = 0 this.chatMessageSize = 0
this.imageFile = null this.imageFile = null
this.uid = new ShortUniqueId() this.uid = new ShortUniqueId()
this.caption = "" this.userLanguage = ""
} }
render() { render() {
console.log(this.chatEditorPlaceholder, "here1123")
const mstring = get("chatpage.cchange8");
console.log(mstring, "here5040");
return html` return html`
<div class="chat-container"> <div class="chat-container">
<div> <div>
@ -516,69 +510,6 @@ class ChatPage extends LitElement {
</div> </div>
` : ` :
this.renderChatScroller()} this.renderChatScroller()}
<mwc-dialog
id="showDialogPublicKey"
?open=${this.imageFile}
@closed=${() => {
this.imageFile = null;
this.chatEditor.enable()
}}>
<div class="dialog-header"></div>
<div class="dialog-container mdc-dialog mdc-dialog__surface">
${this.imageFile && html`
<img src=${URL.createObjectURL(this.imageFile)} alt="dialog-img" class="dialog-image" />
`}
<div class="caption-container">
<chat-text-editor
iframeId="newChat"
?hasGlobalEvents=${false}
placeholder=${this.chatEditorPlaceholder}
._sendMessage=${this._sendMessage}
.setChatEditor=${(editor)=> this.setChatEditorNewChat(editor)}
.chatEditor=${this.chatEditorNewChat}
.imageFile=${this.imageFile}
.insertImage=${this.insertImage}
.editedMessageObj=${this.editedMessageObj}
?isLoading=${this.isLoading}
?isLoadingMessages=${this.isLoadingMessages}>
</chat-text-editor>
</div>
${this.chatMessageSize >= 750 ?
html`
<div class="message-size-container">
<div class="message-size" style="${this.chatMessageSize >= 1000 && 'color: #bd1515'}">
${`Your message size is of ${this.chatMessageSize} bytes out of a maximum of 1000`}
</div>
</div>
` :
html``}
</div>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
class="red"
@click=${()=>{
this.imageFile = null
}}
>
${translate("chatpage.cchange33")}
</mwc-button>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
@click=${()=> {
this._sendMessage({
type: 'image',
imageFile: this.imageFile,
})
}}
>
${translate("chatpage.cchange9")}
</mwc-button>
</mwc-dialog>
</div> </div>
<div class="chat-text-area" style="${`${(this.repliedToMessageObj || this.editedMessageObj) && "min-height: 120px"}`}"> <div class="chat-text-area" style="${`${(this.repliedToMessageObj || this.editedMessageObj) && "min-height: 120px"}`}">
<div class="typing-area"> <div class="typing-area">
@ -630,7 +561,8 @@ class ChatPage extends LitElement {
.editedMessageObj=${this.editedMessageObj} .editedMessageObj=${this.editedMessageObj}
.mirrorChatInput=${this.mirrorChatInput} .mirrorChatInput=${this.mirrorChatInput}
?isLoading=${this.isLoading} ?isLoading=${this.isLoading}
?isLoadingMessages=${this.isLoadingMessages}> ?isLoadingMessages=${this.isLoadingMessages}
>
</chat-text-editor> </chat-text-editor>
</div> </div>
</div> </div>
@ -648,32 +580,87 @@ class ChatPage extends LitElement {
</div> </div>
</div> </div>
</div> </div>
`: ''} `: ''}
<wrapper-modal
.removeImage=${() => this.removeImage()}
style=${this.imageFile ? "display: block" : "display: none"}>
<div>
<div class="dialog-container">
${this.imageFile && html`
<img src=${URL.createObjectURL(this.imageFile)} alt="dialog-img" class="dialog-image" />
`}
<div class="caption-container">
<chat-text-editor
iframeId="newChat"
?hasGlobalEvents=${false}
placeholder=${this.chatEditorPlaceholder}
._sendMessage=${this._sendMessage}
.setChatEditor=${(editor)=> this.setChatEditorNewChat(editor)}
.chatEditor=${this.chatEditorNewChat}
.imageFile=${this.imageFile}
.insertImage=${this.insertImage}
.editedMessageObj=${this.editedMessageObj}
?isLoading=${this.isLoading}
?isLoadingMessages=${this.isLoadingMessages}>
</chat-text-editor>
</div>
${this.chatMessageSize >= 750 ?
html`
<div class="message-size-container">
<div class="message-size" style="${this.chatMessageSize >= 1000 && 'color: #bd1515'}">
${`Your message size is of ${this.chatMessageSize} bytes out of a maximum of 1000`}
</div>
</div>
` :
html``}
<button
class="red"
@click=${()=>{
this.imageFile = null
}}
>
${translate("chatpage.cchange33")}
</button>
<button
@click=${()=> {
this._sendMessage({
type: 'image',
imageFile: this.imageFile,
})
}}
>
${translate("chatpage.cchange9")}
</button>
</div>
</div>
</wrapper-modal>
</div> </div>
` `
} }
setChatEditor(editor){ setChatEditor(editor) {
this.chatEditor = editor this.chatEditor = editor;
} }
setChatEditorNewChat(editor){ setChatEditorNewChat(editor) {
this.chatEditorNewChat = editor this.chatEditorNewChat = editor;
} }
insertImage(file){ insertImage(file){
if (file.type.includes('image')) {
if(file.type.includes('image')){ this.imageFile = file;
this.imageFile = file this.chatEditor.disable();
this.chatEditor.disable()
// this.changeMsgInput('newChat') // this.changeMsgInput('newChat')
// this.initChatEditor(); // this.initChatEditor();
// this.chatEditor.disable(); // this.chatEditor.disable();
return return;
} }
parentEpml.request('showSnackBar', get("chatpage.cchange28"));
parentEpml.request('showSnackBar', get("chatpage.cchange28")) }
removeImage() {
this.imageFile = null;
this.chatEditor.enable();
} }
changeMsgInput(id){ changeMsgInput(id){
@ -684,7 +671,6 @@ class ChatPage extends LitElement {
} }
async firstUpdated() { async firstUpdated() {
// TODO: Load and fetch messages from localstorage (maybe save messages to localstorage...) // TODO: Load and fetch messages from localstorage (maybe save messages to localstorage...)
// document.addEventListener('keydown', (e) => { // document.addEventListener('keydown', (e) => {
@ -701,9 +687,11 @@ class ChatPage extends LitElement {
// } // }
// }); // });
window.addEventListener('storage', () => { window.addEventListener('storage', () => {
const checkLanguage = localStorage.getItem('qortalLanguage') const checkLanguage = localStorage.getItem('qortalLanguage');
use(checkLanguage) use(checkLanguage);
console.log(checkLanguage, "language here");
this.userLanguage = checkLanguage;
}) })
const getAddressPublicKey = () => { const getAddressPublicKey = () => {
@ -733,14 +721,15 @@ class ChatPage extends LitElement {
}; };
setTimeout(() => { setTimeout(() => {
const isRecipient = this.chatId.includes('direct') === true ? true : false;
this.chatId.includes('direct') === true ? this.isReceipient = true : this.isReceipient = false; this.chatId.includes('direct') === true ? this.isReceipient = true : this.isReceipient = false;
this._chatId = this.chatId.split('/')[1]; this._chatId = this.chatId.split('/')[1];
const mstring = get("chatpage.cchange8");
const mstring = get("chatpage.cchange8") console.log(mstring, "here5090");
const placeholder = this.isReceipient === true ? `Message ${this._chatId}` : `${mstring}`; const placeholder = isRecipient === true ? `Message ${this._chatId}` : `${mstring}`;
this.chatEditorPlaceholder = placeholder; this.chatEditorPlaceholder = placeholder;
this.isReceipient ? getAddressPublicKey() : this.fetchChatMessages(this._chatId); isRecipient ? getAddressPublicKey() : this.fetchChatMessages(this._chatId);
// Init ChatEditor // Init ChatEditor
// this.initChatEditor(); // this.initChatEditor();
@ -771,26 +760,16 @@ class ChatPage extends LitElement {
parentEpml.imReady(); parentEpml.imReady();
} }
async updated(changedProperties) {
if (changedProperties && changedProperties.has('userLanguage')) {
await new Promise(r => setTimeout(r, 100));
onCaptionChange(e) { this.chatEditorPlaceholder = this.isReceipient === true ? `Message ${this._chatId}` : `${get("chatpage.cchange8")}`;
this.caption = e;
}
changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage')
if (checkLanguage === null || checkLanguage.length === 0) {
localStorage.setItem('qortalLanguage', 'us')
use('us')
} else {
use(checkLanguage)
} }
} }
renderPlaceholder() { renderPlaceholder() {
const mstring = get("chatpage.cchange8") const mstring = get("chatpage.cchange8");
console.log(mstring, "here11");
const placeholder = this.isReceipient === true ? `Message ${this._chatId}` : `${mstring}`; const placeholder = this.isReceipient === true ? `Message ${this._chatId}` : `${mstring}`;
return placeholder; return placeholder;
} }
@ -832,10 +811,10 @@ class ChatPage extends LitElement {
const replacedMessages = await replaceMessagesEdited({ const replacedMessages = await replaceMessagesEdited({
decodedMessages: decodeMsgs, decodedMessages: decodeMsgs,
parentEpml, parentEpml,
isReceipient: this.isReceipient, isReceipient: this.isReceipient,
decodeMessageFunc: this.decodeMessage, decodeMessageFunc: this.decodeMessage,
_publicKey: this._publicKey _publicKey: this._publicKey
}) })
this.messagesRendered = [...replacedMessages, ...this.messagesRendered].sort(function (a, b) { this.messagesRendered = [...replacedMessages, ...this.messagesRendered].sort(function (a, b) {
return a.timestamp return a.timestamp
@ -858,10 +837,10 @@ class ChatPage extends LitElement {
const replacedMessages = await replaceMessagesEdited({ const replacedMessages = await replaceMessagesEdited({
decodedMessages: decodeMsgs, decodedMessages: decodeMsgs,
parentEpml, parentEpml,
isReceipient: this.isReceipient, isReceipient: this.isReceipient,
decodeMessageFunc: this.decodeMessage, decodeMessageFunc: this.decodeMessage,
_publicKey: this._publicKey _publicKey: this._publicKey
}) })
this.messagesRendered = [...replacedMessages, ...this.messagesRendered].sort(function (a, b) { this.messagesRendered = [...replacedMessages, ...this.messagesRendered].sort(function (a, b) {
@ -892,7 +871,7 @@ class ChatPage extends LitElement {
}) })
if (isInitial) { if (isInitial) {
this.chatEditorPlaceholder = this.renderPlaceholder();
const replacedMessages = await replaceMessagesEdited({ const replacedMessages = await replaceMessagesEdited({
decodedMessages: decodedMessages, decodedMessages: decodedMessages,
parentEpml, parentEpml,
@ -932,7 +911,6 @@ class ChatPage extends LitElement {
} }
} }
// set replied to message in chat editor // set replied to message in chat editor
setRepliedToMessageObj(messageObj) { setRepliedToMessageObj(messageObj) {

38
qortal-ui-plugins/plugins/core/components/ChatScroller-css.js

@ -168,7 +168,7 @@ export const chatStyles = css`
.message-reactions { .message-reactions {
background-color: transparent; background-color: transparent;
width: 100%; width: calc(100% - 54px);
margin-left: 54px; margin-left: 54px;
} }
@ -296,8 +296,8 @@ export const chatStyles = css`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
background-color: white; background-color: var(--chat-menu-bg);
border: 1px solid #dad9d9; border: 1px solid var(--chat-menu-outline);
border-radius: 5px; border-radius: 5px;
height:100%; height:100%;
position: relative; position: relative;
@ -313,11 +313,12 @@ export const chatStyles = css`
display: flex; display: flex;
align-items: center; align-items: center;
font-size: 13px; font-size: 13px;
color: var(--chat-menu-icon);
} }
.menu-icon:hover { .menu-icon:hover {
border-radius: 5px; border-radius: 5px;
background-color: #dad9d9; background-color: var(--chat-menu-icon-hover);
transition: all 0.1s ease-in-out; transition: all 0.1s ease-in-out;
cursor: pointer; cursor: pointer;
} }
@ -372,16 +373,28 @@ export const chatStyles = css`
} }
.block-user { .block-user {
justify-content: space-between; width: 100%;
padding: 5px 7px;
display: flex;
align-items: center;
font-size: 13px;
color: var(--chat-menu-icon);
justify-content: space-evenly;
border: 1px solid rgb(218, 217, 217); border: 1px solid rgb(218, 217, 217);
border-radius: 5px; border-radius: 5px;
background-color: white; background-color: var(--chat-menu-bg);
width: 90px; width: 150px;
height: 32px; height: 32px;
padding: 3px 8px; padding: 3px 8px;
box-shadow: rgba(77, 77, 82, 0.2) 0px 7px 29px 0px; box-shadow: rgba(77, 77, 82, 0.2) 0px 7px 29px 0px;
} }
.block-user:hover {
cursor:pointer;
background-color: var(--block-user-bg-hover);
transition: all 0.1s ease-in-out 0s;
}
.reactions-bg { .reactions-bg {
background-color: #d5d5d5; background-color: #d5d5d5;
border-radius: 10px; border-radius: 10px;
@ -394,7 +407,7 @@ export const chatStyles = css`
} }
.reactions-bg:hover { .reactions-bg:hover {
border: 0.5px solid #6b6969; border: 0.5px solid var(--reaction-bubble-outline);
} }
.image-container { .image-container {
@ -412,6 +425,15 @@ export const chatStyles = css`
height: 40vh; height: 40vh;
} }
.image-deleted-msg {
font-family: Roboto, sans-serif;
font-size: 14px;
font-style: italic;
color: var(--chat-bubble-msg-color);
margin: 0;
padding-top: 10px;
}
.image-delete-icon { .image-delete-icon {
margin-left: 5px; margin-left: 5px;
height: 20px; height: 20px;

7
qortal-ui-plugins/plugins/core/components/ChatScroller.js

@ -416,8 +416,7 @@ class MessageTemplate extends LitElement {
${image && !isImageDeleted ? html` ${image && !isImageDeleted ? html`
<div <div
class=${[`image-container`, !this.isImageLoaded ? 'defaultSize' : ''].join(' ')} class=${[`image-container`, !this.isImageLoaded ? 'defaultSize' : ''].join(' ')}
style=${this.isFirstMessage && "margin-top: 10px;"} style=${this.isFirstMessage && "margin-top: 10px;"}>
>
${imageHTML}<vaadin-icon ${imageHTML}<vaadin-icon
@click=${() => this.sendMessage({ @click=${() => this.sendMessage({
type: 'delete', type: 'delete',
@ -427,6 +426,8 @@ class MessageTemplate extends LitElement {
})} })}
class="image-delete-icon" icon="vaadin:close" slot="icon"></vaadin-icon> class="image-delete-icon" icon="vaadin:close" slot="icon"></vaadin-icon>
</div> </div>
` : image && isImageDeleted ? html`
<p class="image-deleted-msg">This image has been deleted</p>
` : html``} ` : html``}
<div <div
id="messageContent" id="messageContent"
@ -630,7 +631,7 @@ editedMessageObj: this.originalMessage,
${this.showBlockAddressIcon ${this.showBlockAddressIcon
? html` ? html`
<div class="block-user-container"> <div class="block-user-container">
<div class="menu-icon block-user" @click="${() => this.showBlockUserModal()}"> <div class="block-user" @click="${() => this.showBlockUserModal()}">
<p>${translate("blockpage.bcchange1")}</p> <p>${translate("blockpage.bcchange1")}</p>
<vaadin-icon icon="vaadin:close-circle" slot="icon"></vaadin-icon> <vaadin-icon icon="vaadin:close-circle" slot="icon"></vaadin-icon>
</div> </div>

246
qortal-ui-plugins/plugins/core/components/ChatTextEditor.js

@ -1,25 +1,30 @@
import { LitElement, html, css } from "lit" import { LitElement, html, css } from "lit";
import { render } from "lit/html.js" import { get } from 'lit-translate';
import { escape, unescape } from 'html-escaper'; import { escape, unescape } from 'html-escaper';
import { EmojiPicker } from 'emoji-picker-js'; import { EmojiPicker } from 'emoji-picker-js';
import { inputKeyCodes } from '../../utils/keyCodes.js' import { inputKeyCodes } from '../../utils/keyCodes.js';
import { Epml } from '../../../epml.js';
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
class ChatTextEditor extends LitElement { class ChatTextEditor extends LitElement {
static get properties() { static get properties() {
return { return {
isLoading: { type: Boolean }, isLoading: { type: Boolean },
isLoadingMessages: { type: Boolean }, isLoadingMessages: { type: Boolean },
_sendMessage: {attribute: false}, _sendMessage: { attribute: false },
placeholder: {type: String}, placeholder: { type: String },
imageFile: {type: Object}, imageFile: { type: Object },
insertImage: {attribute: false}, insertImage: { attribute: false },
iframeHeight: { type: Number }, iframeHeight: { type: Number },
editedMessageObj: {type: Object}, editedMessageObj: { type: Object },
chatEditor: {type: Object}, chatEditor: { type: Object },
setChatEditor: {attribute: false}, setChatEditor: { attribute: false },
iframeId: {type: String}, iframeId: { type: String },
hasGlobalEvents: {type: Boolean} hasGlobalEvents: { type: Boolean },
theme: {
type: String,
reflect: true
}
} }
} }
@ -42,6 +47,10 @@ class ChatTextEditor extends LitElement {
overflow: hidden; overflow: hidden;
} }
.chatbar-caption {
border-bottom: 2px solid var(--mdc-theme-primary);
}
.emoji-button { .emoji-button {
width: 45px; width: 45px;
height: 40px; height: 40px;
@ -65,8 +74,9 @@ class ChatTextEditor extends LitElement {
font-size: 12px; font-size: 12px;
color: black; color: black;
} }
.paperclip-icon { .paperclip-icon {
color: #494949; color: var(--paperclip-icon);
width: 25px; width: 25px;
} }
@ -132,81 +142,93 @@ class ChatTextEditor extends LitElement {
this.removeGlobalEventListener = this.removeGlobalEventListener.bind(this) this.removeGlobalEventListener = this.removeGlobalEventListener.bind(this)
this.initialChat = this.initialChat.bind(this) this.initialChat = this.initialChat.bind(this)
this.iframeHeight = 42 this.iframeHeight = 42
this.userName = window.parent.reduxStore.getState().app.accountInfo.names[0];
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light';
} }
render() { render() {
console.log(this.theme)
return html` return html`
<div class="chatbar-container" style="${this.chatMessageInput && this.chatMessageInput.contentDocument.body.scrollHeight > 60 ? 'align-items: flex-end' : "align-items: center"}" <div
class=${["chatbar-container", this.iframeId === "newChat" ? "chatbar-caption" : ""].join(" ")}
style="${this.chatMessageInput && this.chatMessageInput.contentDocument.body.scrollHeight > 60 ? 'align-items: flex-end' : "align-items: center"}">
<div class="file-picker-container" @click=${(e) => {
this.preventUserSendingImage(e)
}}>
<vaadin-icon
class="paperclip-icon"
icon="vaadin:paperclip"
slot="icon"
>
</vaadin-icon>
<div class="file-picker-input-container">
<input
.value="${this.imageFile}"
@change="${e => this.insertImage(e.target.files[0])}"
class="file-picker-input" type="file" name="myImage" accept="image/*" />
</div>
</div>
<textarea style="color: var(--black);" tabindex='1' ?autofocus=${true} ?disabled=${this.isLoading || this.isLoadingMessages} id="messageBox" rows="1"></textarea>
<iframe
}}" id=${this.iframeId} class="chat-editor" tabindex="-1" height=${this.iframeHeight}>
</iframe>
<button class="emoji-button" ?disabled=${this.isLoading || this.isLoadingMessages}>
${html`<img class="emoji" draggable="false" alt="😀" src="/emoji/svg/1f600.svg" />`}
</button>
${this.editedMessageObj ? (
html`
<div>
${this.isLoading === false ? html`
<vaadin-icon
class="checkmark-icon"
icon="vaadin:check"
slot="icon"
@click=${() => this._sendMessage()}
> >
<div class="file-picker-container"> </vaadin-icon>
<vaadin-icon ` :
class="paperclip-icon" html`
icon="vaadin:paperclip" <paper-spinner-lite active></paper-spinner-lite>
slot="icon" `}
> </div>
</vaadin-icon> `
<div class="file-picker-input-container"> ) :
<input html`
.value="${this.imageFile}" <div style="${this.chatMessageInput && this.chatMessageInput.contentDocument.body.scrollHeight > 60 ? 'margin-bottom: 5px;' : "margin-bottom: 0;"} ${this.iframeId === 'newChat' ? 'display: none;' : 'display: flex;'}">
@change="${e => this.insertImage(e.target.files[0])}" ${this.isLoading === false ? html`
class="file-picker-input" type="file" name="myImage" accept="image/*" /> <img
</div> src="/img/qchat-send-message-icon.svg"
</div> alt="send-icon"
<textarea style="color: var(--black);" tabindex='1' ?autofocus=${true} ?disabled=${this.isLoading || this.isLoadingMessages} id="messageBox" rows="1"></textarea> class="send-icon"
<iframe @click=${() => this._sendMessage()} />
}}" id=${this.iframeId} class="chat-editor" tabindex="-1" height=${this.iframeHeight}> ` :
</iframe> html`
<button class="emoji-button" ?disabled=${this.isLoading || this.isLoadingMessages}> <paper-spinner-lite active></paper-spinner-lite>
${html`<img class="emoji" draggable="false" alt="😀" src="/emoji/svg/1f600.svg" />`} `}
</button>
${this.editedMessageObj ? (
html`
<div>
${this.isLoading === false ? html`
<vaadin-icon
class="checkmark-icon"
icon="vaadin:check"
slot="icon"
@click=${() => this._sendMessage()}
>
</vaadin-icon>
` :
html`
<paper-spinner-lite active></paper-spinner-lite>
`}
</div>
`
) :
html`
<div style="display:flex; ${this.chatMessageInput && this.chatMessageInput.contentDocument.body.scrollHeight > 60 ? 'margin-bottom: 5px' : "margin-bottom: 0"}">
${this.isLoading === false ? html`
<img
src="/img/qchat-send-message-icon.svg"
alt="send-icon"
class="send-icon"
@click=${() => this._sendMessage()} />
` :
html`
<paper-spinner-lite active></paper-spinner-lite>
`}
</div>
`
}
</div>
${this.chatMessageSize >= 750 ?
html`
<div class="message-size-container">
<div class="message-size" style="${this.chatMessageSize >= 1000 && 'color: #bd1515'}">
${`Your message size is of ${this.chatMessageSize} bytes out of a maximum of 1000`}
</div>
</div>
` :
html``}
</div> </div>
`
}
</div>
${this.chatMessageSize >= 750 ?
html`
<div class="message-size-container">
<div class="message-size" style="${this.chatMessageSize >= 1000 && 'color: #bd1515'}">
${`Your message size is of ${this.chatMessageSize} bytes out of a maximum of 1000`}
</div>
</div>
` :
html``}
</div>
` `
} }
preventUserSendingImage(e) {
if (!this.userName) {
e.preventDefault();
parentEpml.request('showSnackBar', get("chatpage.cchange27"));
};
}
initialChat(e) { initialChat(e) {
if (!this.chatEditor?.contentDiv.matches(':focus')) { if (!this.chatEditor?.contentDiv.matches(':focus')) {
// WARNING: Deprecated methods from KeyBoard Event // WARNING: Deprecated methods from KeyBoard Event
@ -230,14 +252,27 @@ class ChatTextEditor extends LitElement {
} }
async firstUpdated() { async firstUpdated() {
if(this.hasGlobalEvents){ console.log(this.placeholder, "here500");
this.addGlobalEventListener() if (this.hasGlobalEvents) {
this.addGlobalEventListener();
} }
window.addEventListener('storage', () => {
const checkTheme = localStorage.getItem('qortalTheme');
const captionEditor = this.shadowRoot.getElementById(this.iframeId).contentWindow.document.getElementById('testingId')
if (checkTheme === 'dark') {
this.theme = 'dark';
captionEditor.style.cssText = "color:#ffffff;"
} else {
this.theme = 'light';
captionEditor.style.cssText = "color:#080808;"
}
})
this.emojiPickerHandler = this.shadowRoot.querySelector('.emoji-button'); this.emojiPickerHandler = this.shadowRoot.querySelector('.emoji-button');
this.mirrorChatInput = this.shadowRoot.getElementById('messageBox'); this.mirrorChatInput = this.shadowRoot.getElementById('messageBox');
this.chatMessageInput = this.shadowRoot.getElementById(this.iframeId); this.chatMessageInput = this.shadowRoot.getElementById(this.iframeId);
this.emojiPicker = new EmojiPicker({ this.emojiPicker = new EmojiPicker({
style: "twemoji", style: "twemoji",
@ -267,7 +302,11 @@ class ChatTextEditor extends LitElement {
if (changedProperties && changedProperties.has('editedMessageObj')) { if (changedProperties && changedProperties.has('editedMessageObj')) {
this.chatEditor.insertText(this.editedMessageObj.message) this.chatEditor.insertText(this.editedMessageObj.message)
} }
if (changedProperties && changedProperties.has('placeholder')) {
console.log(this.placeholder, "here600");
const captionEditor = this.shadowRoot.getElementById(this.iframeId).contentWindow.document.getElementById('testingId');
captionEditor.setAttribute('data-placeholder', this.placeholder);
}
} }
shouldUpdate(changedProperties) { shouldUpdate(changedProperties) {
@ -327,20 +366,15 @@ class ChatTextEditor extends LitElement {
} }
calculateIFrameHeight(height) { calculateIFrameHeight(height) {
setTimeout(()=> { setTimeout(()=> {
const editorTest = this.shadowRoot.getElementById(this.iframeId).contentWindow.document.getElementById('testingId').scrollHeight const editorTest = this.shadowRoot.getElementById(this.iframeId).contentWindow.document.getElementById('testingId').scrollHeight;
this.iframeHeight = editorTest + 20;
this.iframeHeight = editorTest + 20
}, 50) }, 50)
} }
initChatEditor() { initChatEditor() {
const ChatEditor = function (editorConfig) { const ChatEditor = function (editorConfig) {
console.log(editorConfig.placeholder, "here5600");
const ChatEditor = function () { const ChatEditor = function () {
const editor = this; const editor = this;
editor.init(); editor.init();
@ -382,6 +416,7 @@ class ChatTextEditor extends LitElement {
html { html {
cursor: text; cursor: text;
} }
div { div {
font-size: 1rem; font-size: 1rem;
line-height: 1.38rem; line-height: 1.38rem;
@ -394,6 +429,7 @@ class ChatTextEditor extends LitElement {
outline: none; outline: none;
min-height: 20px; min-height: 20px;
} }
div[contentEditable=true]:empty:before { div[contentEditable=true]:empty:before {
content: attr(data-placeholder); content: attr(data-placeholder);
display: block; display: block;
@ -403,9 +439,11 @@ class ChatTextEditor extends LitElement {
user-select: none; user-select: none;
white-space: nowrap; white-space: nowrap;
} }
div[contentEditable=false]{ div[contentEditable=false]{
background: rgba(0,0,0,0.1); background: rgba(0,0,0,0.1);
} }
img.emoji { img.emoji {
width: 1.7em; width: 1.7em;
height: 1.5em; height: 1.5em;
@ -611,7 +649,6 @@ class ChatTextEditor extends LitElement {
} }
editor.content.addEventListener('click', function (event) { editor.content.addEventListener('click', function (event) {
event.preventDefault(); event.preventDefault();
editor.focus(); editor.focus();
}); });
@ -619,7 +656,7 @@ class ChatTextEditor extends LitElement {
ChatEditor.prototype.remove = function () { ChatEditor.prototype.remove = function () {
const editor = this; const editor = this;
var old_element = editor.content.body var old_element = editor.content.body;
var new_element = old_element.cloneNode(true); var new_element = old_element.cloneNode(true);
editor.content.body.parentNode.replaceChild(new_element, old_element); editor.content.body.parentNode.replaceChild(new_element, old_element);
while (editor.content.body.firstChild) { while (editor.content.body.firstChild) {
@ -640,10 +677,10 @@ class ChatTextEditor extends LitElement {
elemDiv.setAttribute('contenteditable', 'true'); elemDiv.setAttribute('contenteditable', 'true');
elemDiv.setAttribute('spellcheck', 'false'); elemDiv.setAttribute('spellcheck', 'false');
elemDiv.setAttribute('data-placeholder', editorConfig.placeholder); elemDiv.setAttribute('data-placeholder', editorConfig.placeholder);
elemDiv.style.cssText = 'width:100%'; elemDiv.style.cssText = `width:100%; ${editorConfig.theme === "dark" ? "color:#ffffff;" : "color: #080808"}`;
elemDiv.id = 'testingId' elemDiv.id = 'testingId';
editor.content.body.appendChild(elemDiv); editor.content.body.appendChild(elemDiv);
editor.contentDiv = editor.frame.contentDocument.body.firstChild editor.contentDiv = editor.frame.contentDocument.body.firstChild;
editor.styles(); editor.styles();
editor.listenChanges(); editor.listenChanges();
@ -672,10 +709,11 @@ editor.content.body.appendChild(elemDiv);
chatMessageSize: this.chatMessageSize, chatMessageSize: this.chatMessageSize,
addGlobalEventListener: this.addGlobalEventListener, addGlobalEventListener: this.addGlobalEventListener,
removeGlobalEventListener: this.removeGlobalEventListener, removeGlobalEventListener: this.removeGlobalEventListener,
iframeId: this.iframeId iframeId: this.iframeId,
theme: this.theme
}; };
const newChat = new ChatEditor(editorConfig) const newChat = new ChatEditor(editorConfig);
this.setChatEditor(newChat) this.setChatEditor(newChat);
} }
} }

55
qortal-ui-plugins/plugins/core/components/WrapperModal-css.js

@ -0,0 +1,55 @@
import { css } from 'lit'
export const wrapperModalStyles = css`
.backdrop {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgb(186 186 186 / 26%);
overflow: hidden;
animation: backdrop_blur cubic-bezier(0.22, 1, 0.36, 1) 1s forwards;
}
.modal-body {
height: auto;
position: fixed;
box-shadow: rgb(60 64 67 / 30%) 0px 1px 2px 0px, rgb(60 64 67 / 15%) 0px 2px 6px 2px;
width: 500px;
z-index: 5;
display: flex;
flex-direction: column;
padding: 15px;
background-color: var(--white);
left: 50%;
top: 0px;
transform: translate(-50%, 40%);
border-radius: 12px;
overflow-y: auto;
animation: 1s cubic-bezier(0.22, 1, 0.36, 1) 0s 1 normal forwards running modal_transition;
max-height: 80%;
}
@keyframes backdrop_blur {
0% {
backdrop-filter: blur(0px);
background: transparent;
}
100% {
backdrop-filter: blur(5px);
background: rgb(186 186 186 / 26%);
}
}
@keyframes modal_transition {
0% {
visibility: hidden;
opacity: 0;
}
100% {
visibility: visible;
opacity: 1;
}
}
`

27
qortal-ui-plugins/plugins/core/components/WrapperModal.js

@ -0,0 +1,27 @@
import { LitElement, html } from 'lit';
import { render } from 'lit/html.js';
import { wrapperModalStyles } from './WrapperModal-css.js'
export class WrapperModal extends LitElement {
static get properties() {
return {
removeImage: { type: Function },
}
}
static styles = [wrapperModalStyles]
render() {
return html`
<div>
<div class="backdrop" @click=${() => {
this.removeImage()
}}></div>
<div class="modal-body">
<slot></slot>
</div>
</div>
`;
}
}
customElements.define('wrapper-modal', WrapperModal);
Loading…
Cancel
Save