Feat (user): add option to change group name

Feat (user): add option to change group description

Feat (dev): add new component 'text-field' for quick editing text
This commit is contained in:
sairaj mote 2021-01-26 04:04:42 +05:30
parent 64c108ae59
commit 34aadc61f1
5 changed files with 356 additions and 121 deletions

View File

@ -313,13 +313,6 @@ sm-popup sm-input + sm-input {
margin: 1rem 0; margin: 1rem 0;
} }
sm-button {
margin: 1rem 0;
}
sm-button .icon {
margin-right: 0.4rem;
}
sm-button[variant=primary] { sm-button[variant=primary] {
--foreground-color: 255, 255, 255; --foreground-color: 255, 255, 255;
} }
@ -671,14 +664,11 @@ sm-button[variant=primary] .icon {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
#contact_details_popup #contact_name { #contact_details_popup #contact_name {
border-radius: 0.5rem; margin: 0.6rem 0;
max-width: 30ch;
padding: 0.6rem 1.2rem;
overflow-wrap: break-word;
} }
#contact_details_popup #contact_name:focus { #contact_details_popup #contact_name::part(text) {
outline: none; font-size: 1.2rem;
background: rgba(var(--text-color), 0.1); font-weight: 500;
} }
#warn_no_encryption, .date-card, .group-event-card { #warn_no_encryption, .date-card, .group-event-card {
@ -1215,6 +1205,7 @@ sm-button[variant=primary] .icon {
border-color: var(--accent-color) transparent transparent transparent; border-color: var(--accent-color) transparent transparent transparent;
} }
#chat .received { #chat .received {
margin-right: auto;
background: rgba(var(--text-color), 0.1); background: rgba(var(--text-color), 0.1);
border-radius: 0 0.8rem 0.8rem 0.8rem; border-radius: 0 0.8rem 0.8rem 0.8rem;
} }
@ -1283,7 +1274,7 @@ sm-button[variant=primary] .icon {
} }
#scroll_to_bottom { #scroll_to_bottom {
position: absolute; position: fixed;
display: flex; display: flex;
right: 0; right: 0;
bottom: 4rem; bottom: 4rem;
@ -1373,10 +1364,6 @@ sm-button[variant=primary] .icon {
padding: 0 1rem; padding: 0 1rem;
} }
#messages_container {
height: 100%;
}
#emoji_picker { #emoji_picker {
display: grid; display: grid;
gap: 1rem; gap: 1rem;
@ -1828,7 +1815,8 @@ sm-panel {
} }
.navbar-item:hover, .navbar-item:hover,
.contact:hover { .contact:hover,
.emoji:hover {
cursor: pointer; cursor: pointer;
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
} }

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -268,12 +268,6 @@ sm-popup{
flex-direction: column; flex-direction: column;
margin: 1rem 0; margin: 1rem 0;
} }
sm-button{
margin: 1rem 0;
.icon{
margin-right: 0.4rem;
}
}
sm-button[variant="primary"]{ sm-button[variant="primary"]{
--foreground-color: 255, 255, 255; --foreground-color: 255, 255, 255;
.icon{ .icon{
@ -623,13 +617,10 @@ sm-button[variant="primary"]{
margin-bottom: 1rem; margin-bottom: 1rem;
} }
#contact_name{ #contact_name{
border-radius: 0.5rem; margin: 0.6rem 0;
max-width: 30ch; &::part(text){
padding: 0.6rem 1.2rem; font-size: 1.2rem;
overflow-wrap: break-word; font-weight: 500;
&:focus{
outline: none;
background: rgba(var(--text-color), 0.1);
} }
} }
} }
@ -1149,6 +1140,7 @@ sm-button[variant="primary"]{
} }
} }
.received{ .received{
margin-right: auto;
background: rgba(var(--text-color), 0.1); background: rgba(var(--text-color), 0.1);
border-radius: 0 0.8rem 0.8rem 0.8rem; border-radius: 0 0.8rem 0.8rem 0.8rem;
&::after{ &::after{
@ -1216,7 +1208,7 @@ sm-button[variant="primary"]{
} }
} }
#scroll_to_bottom{ #scroll_to_bottom{
position: absolute; position: fixed;
display: flex; display: flex;
right: 0; right: 0;
bottom: 4rem; bottom: 4rem;
@ -1304,9 +1296,6 @@ sm-button[variant="primary"]{
flex: 1; flex: 1;
padding: 0 1rem; padding: 0 1rem;
} }
#messages_container{
height: 100%;
}
#emoji_picker{ #emoji_picker{
display: grid; display: grid;
gap: 1rem; gap: 1rem;
@ -1728,7 +1717,8 @@ sm-panel{
} }
} }
.navbar-item:hover, .navbar-item:hover,
.contact:hover{ .contact:hover,
.emoji:hover{
cursor: pointer; cursor: pointer;
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
} }

View File

@ -219,12 +219,8 @@
</header> </header>
<div class="flex direction-column align-center"> <div class="flex direction-column align-center">
<div id="contact_initial" class="initial flex align-center"></div> <div id="contact_initial" class="initial flex align-center"></div>
<h4 id="contact_name" ondblclick="setNameEditable()"></h4> <text-field id="contact_name"></text-field>
<div class="flex space-between align-center"> <div class="flex space-between align-center">
<svg tooltip="Edit" id="edit_contact_name" class="icon" onclick="setNameEditable()" viewBox="0 0 64 64">
<path
d="M46.73,14.81l7,7,7.65-7.6A7.15,7.15,0,0,0,61.39,4L60.11,2.77a7.23,7.23,0,0,0-10.19,0L3.87,48.57a5,5,0,0,0-1.39,2.6L.53,61.27a1.74,1.74,0,0,0,2,2l10.15-1.94A5.06,5.06,0,0,0,15.34,60L49.6,25.9" />
</svg>
<svg id="delete_person" onclick="deleteChat()" class="icon" viewBox="0 0 64 64" title="Remove"> <svg id="delete_person" onclick="deleteChat()" class="icon" viewBox="0 0 64 64" title="Remove">
<title>remove</title> <title>remove</title>
<line x1="4" y1="6.3" x2="60" y2="6.3" /> <line x1="4" y1="6.3" x2="60" y2="6.3" />
@ -456,7 +452,7 @@
<footer id="chat_footer" class="grid"> <footer id="chat_footer" class="grid">
<div id="emoji_picker" class="hide-completely"></div> <div id="emoji_picker" class="hide-completely"></div>
<div class="flex"> <div class="flex">
<svg id="emoji_toggle" onclick="toggleEmoji()" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M32,0A32,32,0,1,0,64,32,32,32,0,0,0,32,0ZM43.84,17.51a4.92,4.92,0,1,1-4.92,4.92A4.92,4.92,0,0,1,43.84,17.51Zm-23.62-.06a5,5,0,1,1-5,5A5,5,0,0,1,20.22,17.45ZM32,54.42A19.68,19.68,0,0,1,12.31,34.73H51.69A19.68,19.68,0,0,1,32,54.42Z"/></svg> <svg id="emoji_toggle" onclick="toggleEmoji('toggle')" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M32,0A32,32,0,1,0,64,32,32,32,0,0,0,32,0ZM43.84,17.51a4.92,4.92,0,1,1-4.92,4.92A4.92,4.92,0,0,1,43.84,17.51Zm-23.62-.06a5,5,0,1,1-5,5A5,5,0,0,1,20.22,17.45ZM32,54.42A19.68,19.68,0,0,1,12.31,34.73H51.69A19.68,19.68,0,0,1,32,54.42Z"/></svg>
<sm-textarea id="type_message" placeholder="Type a message" class="rest"></sm-textarea> <sm-textarea id="type_message" placeholder="Type a message" class="rest"></sm-textarea>
<svg xmlns="http://www.w3.org/2000/svg" id="send_message_button" class="icon" viewBox="0 0 64 64"> <svg xmlns="http://www.w3.org/2000/svg" id="send_message_button" class="icon" viewBox="0 0 64 64">
<path d="M63.34,31,3.07,4.71A2.19,2.19,0,0,0,.18,7.58L8.94,28.29,42.18,32,8.94,35.71.18,56.42a2.19,2.19,0,0,0,2.89,2.87L63.34,33A1.09,1.09,0,0,0,63.34,31Z"/> <path d="M63.34,31,3.07,4.71A2.19,2.19,0,0,0,.18,7.58L8.94,28.29,42.18,32,8.94,35.71.18,56.42a2.19,2.19,0,0,0,2.89,2.87L63.34,33A1.09,1.09,0,0,0,63.34,31Z"/>
@ -490,17 +486,16 @@
</div> </div>
<div id="group_description_card" class="card hide-completely"> <div id="group_description_card" class="card hide-completely">
<h4>Group description</h4> <h4>Group description</h4>
<p id="group_description"></p> <text-field id="group_description"></text-field>
</div> </div>
<div id="group_members_card" class="card hide-completely"> <div id="group_members_card" class="card hide-completely">
<div class="flex align-center"> <h4>Group members</h4>
<h4>Group members</h4>
<sm-button class="admin-option justify-right round">Add member</sm-button>
</div>
<div id="group_members_list"></div> <div id="group_members_list"></div>
<sm-button class="admin-option">Add member</sm-button>
</div> </div>
<div class="card"> <div class="card">
<sm-button>Clear chat</sm-button> <sm-button>Clear chat</sm-button>
<sm-button>Delete chat</sm-button>
</div> </div>
</div> </div>
</div> </div>
@ -770,14 +765,21 @@
switch (e.detail.popup.id) { switch (e.detail.popup.id) {
case 'contact_details_popup': case 'contact_details_popup':
if(floGlobals.groups[clickedContact.floID]) if(clickedContact.isGroup){
getRef("contact_initial").innerHTML = ` getRef("contact_initial").innerHTML = `
<svg class="icon group-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M13.61,28.09c-1.63,0-4.72-2.35-5.33-3.58a21.65,21.65,0,0,1-1.35-7.32s-.26-6.07,6.68-6.07a6.38,6.38,0,0,1,6.69,6.07A21.65,21.65,0,0,1,19,24.51c-.62,1.23-3.7,3.58-5.34,3.58"/><path d="M50.39,28.09c-1.64,0-4.72-2.35-5.34-3.58a21.9,21.9,0,0,1-1.35-7.32s-.26-6.07,6.69-6.07a6.37,6.37,0,0,1,6.68,6.07,21.65,21.65,0,0,1-1.35,7.32c-.61,1.23-3.7,3.58-5.33,3.58"/><path d="M32,31.74c-2.21,0-6.37-3.17-7.2-4.83A29.3,29.3,0,0,1,23,17s-.35-8.21,9-8.21c8.68,0,9,8.21,9,8.21a29.3,29.3,0,0,1-1.83,9.88c-.82,1.66-5,4.83-7.2,4.83"/><path d="M48.29,38.58c-4.16-1.83-8.57-3.08-10.34-6.4a12,12,0,0,1-6,3.73,12,12,0,0,1-5.95-3.73c-1.77,3.32-6.18,4.57-10.34,6.4-1.7.71-3.11,9.88-1.13,9.88A33.06,33.06,0,0,0,31.23,53h1.54a33.06,33.06,0,0,0,16.65-4.53C51.4,48.46,50,39.29,48.29,38.58Z"/><path d="M14.82,36.57c.76-.33,1.54-.65,2.3-1,2.49-1,4.85-2,6.22-3.44C21.07,31.23,19,30.25,18,28.41a8.83,8.83,0,0,1-4.41,2.76,8.83,8.83,0,0,1-4.4-2.76c-1.31,2.46-4.58,3.38-7.66,4.74-1.26.52-2.3,7.31-.84,7.31a24.55,24.55,0,0,0,10.86,3.31C11.89,40.81,12.86,37.39,14.82,36.57Z"/><path d="M62.45,33.15c-3.08-1.36-6.35-2.28-7.66-4.74a8.83,8.83,0,0,1-4.4,2.76A8.83,8.83,0,0,1,46,28.41c-1,1.84-3,2.82-5.32,3.76,1.37,1.43,3.73,2.41,6.22,3.44.76.31,1.54.63,2.26,1,2,.83,3,4.25,3.29,7.21a24.55,24.55,0,0,0,10.86-3.31C64.75,40.46,63.71,33.67,62.45,33.15Z"/></svg> <svg class="icon group-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M13.61,28.09c-1.63,0-4.72-2.35-5.33-3.58a21.65,21.65,0,0,1-1.35-7.32s-.26-6.07,6.68-6.07a6.38,6.38,0,0,1,6.69,6.07A21.65,21.65,0,0,1,19,24.51c-.62,1.23-3.7,3.58-5.34,3.58"/><path d="M50.39,28.09c-1.64,0-4.72-2.35-5.34-3.58a21.9,21.9,0,0,1-1.35-7.32s-.26-6.07,6.69-6.07a6.37,6.37,0,0,1,6.68,6.07,21.65,21.65,0,0,1-1.35,7.32c-.61,1.23-3.7,3.58-5.33,3.58"/><path d="M32,31.74c-2.21,0-6.37-3.17-7.2-4.83A29.3,29.3,0,0,1,23,17s-.35-8.21,9-8.21c8.68,0,9,8.21,9,8.21a29.3,29.3,0,0,1-1.83,9.88c-.82,1.66-5,4.83-7.2,4.83"/><path d="M48.29,38.58c-4.16-1.83-8.57-3.08-10.34-6.4a12,12,0,0,1-6,3.73,12,12,0,0,1-5.95-3.73c-1.77,3.32-6.18,4.57-10.34,6.4-1.7.71-3.11,9.88-1.13,9.88A33.06,33.06,0,0,0,31.23,53h1.54a33.06,33.06,0,0,0,16.65-4.53C51.4,48.46,50,39.29,48.29,38.58Z"/><path d="M14.82,36.57c.76-.33,1.54-.65,2.3-1,2.49-1,4.85-2,6.22-3.44C21.07,31.23,19,30.25,18,28.41a8.83,8.83,0,0,1-4.41,2.76,8.83,8.83,0,0,1-4.4-2.76c-1.31,2.46-4.58,3.38-7.66,4.74-1.26.52-2.3,7.31-.84,7.31a24.55,24.55,0,0,0,10.86,3.31C11.89,40.81,12.86,37.39,14.82,36.57Z"/><path d="M62.45,33.15c-3.08-1.36-6.35-2.28-7.66-4.74a8.83,8.83,0,0,1-4.4,2.76A8.83,8.83,0,0,1,46,28.41c-1,1.84-3,2.82-5.32,3.76,1.37,1.43,3.73,2.41,6.22,3.44.76.31,1.54.63,2.26,1,2,.83,3,4.25,3.29,7.21a24.55,24.55,0,0,0,10.86-3.31C64.75,40.46,63.71,33.67,62.45,33.15Z"/></svg>
` `
else if(floGlobals.groups[clickedContact['floID']].admin === myFloID)
getRef('contact_initial').textContent = clickedContact['name'].charAt(0) getRef('contact_name').disabled = false
else
getRef('contact_name').disabled = true
}
else{
getRef('contact_name').disabled = false
getRef('contact_initial').textContent = clickedContact['name'].charAt(0)
}
getRef('contact_initial').setAttribute('style', `background: ${clickedContact['card'].getAttribute('background-color')}`) getRef('contact_initial').setAttribute('style', `background: ${clickedContact['card'].getAttribute('background-color')}`)
getRef('contact_name').textContent = clickedContact['name'] getRef('contact_name').value = clickedContact['name']
getRef('contact_flo_id').textContent = clickedContact['floID'] getRef('contact_flo_id').textContent = clickedContact['floID']
break; break;
} }
@ -788,7 +790,8 @@
let thisPopup = e.detail.popup let thisPopup = e.detail.popup
switch (e.detail.popup.id) { switch (e.detail.popup.id) {
case 'contact_details_popup': case 'contact_details_popup':
clickedContact['name'] = getRef('contact_name').textContent clickedContact['name'] = getRef('contact_name').value.trim()
getRef('contact_name').revert()
break; break;
} }
}) })
@ -1369,7 +1372,7 @@
.catch(error => console.error(error)) .catch(error => console.error(error))
if(prepend){ if(prepend){
getRef('chat_container').prepend(card); getRef('chat_container').prepend(card);
activeChat['receiver'] = floID activeChat['floID'] = floID
if(activeChat['chatCard']) if(activeChat['chatCard'])
activeChat['chatCard'].classList.remove('active') activeChat['chatCard'].classList.remove('active')
getRef('chat_container').children[0].classList.add('active') getRef('chat_container').children[0].classList.add('active')
@ -1381,7 +1384,7 @@
} }
}, },
messageBubble(msg){ messageBubble(msg){
let {admin = false, newMembers = [], groupID, name, sender, floID, message, time: timestamp, category, unconfirmed = false, updateChatCard = false} = msg let {admin = false, newMembers = [], groupID, name, description, sender, floID, message, time: timestamp, category, unconfirmed = false, updateChatCard = false} = msg
let card = getRef('message_template').content.cloneNode(true), let card = getRef('message_template').content.cloneNode(true),
cardContainer = card.querySelector('.message'), cardContainer = card.querySelector('.message'),
messageContent = cardContainer.children[0], messageContent = cardContainer.children[0],
@ -1478,6 +1481,12 @@
eventCard.textContent = `Changed group name to '${name}'` eventCard.textContent = `Changed group name to '${name}'`
return eventCard return eventCard
} }
else if(description){
let eventCard = document.createElement('p')
eventCard.classList.add('group-event-card')
eventCard.textContent = `Changed group description to '${description}'`
return eventCard
}
} }
}, },
@ -1707,11 +1716,7 @@
} }
// detect click outside emoji panel and emoji button // detect click outside emoji panel and emoji button
if(isEmojiPickerOpen && (!e.target.closest('#emoji_picker') && !e.target.closest('#emoji_toggle') && !e.target.closest('#type_message'))){ if(isEmojiPickerOpen && (!e.target.closest('#emoji_picker') && !e.target.closest('#emoji_toggle') && !e.target.closest('#type_message'))){
isEmojiPickerOpen = false toggleEmoji('hide')
getRef('emoji_toggle').classList.remove('active')
getRef('emoji_picker').classList.add('hide-completely')
if(!chatScrollInfo.isScrolledUp)
scrollToBottom()
} }
}) })
@ -1734,6 +1739,8 @@
clickedContact['card'] = contact clickedContact['card'] = contact
clickedContact['floID'] = contact.getAttribute("flo-id") clickedContact['floID'] = contact.getAttribute("flo-id")
clickedContact['name'] = contact.getAttribute("name") clickedContact['name'] = contact.getAttribute("name")
clickedContact['isGroup'] = floGlobals.groups.hasOwnProperty(clickedContact['floID'])
if(clickedContact['floID'] === myFloID) return if(clickedContact['floID'] === myFloID) return
if(e.target.closest(".initial") || e.target.closest(".menu")){ if(e.target.closest(".initial") || e.target.closest(".menu")){
showPopup('contact_details_popup') showPopup('contact_details_popup')
@ -1937,13 +1944,20 @@
} }
renderRecentEmojis() renderRecentEmojis()
function toggleEmoji(button){ function toggleEmoji(mode){
getRef('emoji_toggle').classList.toggle('active') switch(mode){
getRef('emoji_picker').classList.toggle('hide-completely') case 'toggle':
if(getRef('emoji_picker').classList.contains('hide-completely')) isEmojiPickerOpen = true
isEmojiPickerOpen = false getRef('emoji_toggle').classList.toggle('active')
else getRef('emoji_picker').classList.toggle('hide-completely')
isEmojiPickerOpen = true break;
case 'hide':
isEmojiPickerOpen = false
getRef('emoji_toggle').classList.remove('active')
getRef('emoji_picker').classList.add('hide-completely')
break;
}
getRef('scroll_to_bottom').setAttribute('style', `bottom: calc(${window.innerHeight - getRef('chat_footer').getBoundingClientRect().top}px - .5rem)`)
if(!chatScrollInfo.isScrolledUp) if(!chatScrollInfo.isScrolledUp)
scrollToBottom() scrollToBottom()
} }
@ -2176,7 +2190,7 @@
function sendMessage() { function sendMessage() {
if(window.innerWidth > 640) if(window.innerWidth > 640)
getRef('type_message').focusIn() getRef('type_message').focusIn()
let receiver = activeChat['receiver'] let receiver = activeChat['floID']
let container; let container;
let message = getRef('type_message').value.trim(); let message = getRef('type_message').value.trim();
getRef('type_message').value = '' getRef('type_message').value = ''
@ -2184,11 +2198,11 @@
let time = Date.now() let time = Date.now()
let msgObj = {message, time, unconfirmed: true} let msgObj = {message, time, unconfirmed: true}
if(activeChat.isGroup){ if(activeChat.isGroup){
msgObj['groupID'] = activeChat.receiver msgObj['groupID'] = activeChat.floID
msgObj['sender'] = myFloID msgObj['sender'] = myFloID
} }
else{ else{
msgObj['floID'] = activeChat.receiver msgObj['floID'] = activeChat.floID
msgObj['category'] = 'sent' msgObj['category'] = 'sent'
} }
getRef('messages_container').append(render.messageBubble(msgObj)) getRef('messages_container').append(render.messageBubble(msgObj))
@ -2285,7 +2299,7 @@
function scrollToBottom(){ function scrollToBottom(){
if(activeChat.chatCard){ if(activeChat.chatCard){
messenger.removeMark(activeChat.receiver, 'unread') messenger.removeMark(activeChat.floID, 'unread')
activeChat.chatCard.classList.remove('unread') activeChat.chatCard.classList.remove('unread')
} }
getRef('scroll_to_bottom').classList.remove('new-message') getRef('scroll_to_bottom').classList.remove('new-message')
@ -2322,7 +2336,7 @@
for (let i = startIndex; i < endIndex; i++) { for (let i = startIndex; i < endIndex; i++) {
let {floID, groupID, sender, message, time, category} = messages[i] let {floID, groupID, sender, message, time, category} = messages[i]
//Stops message from rendering in wrong chat window //Stops message from rendering in wrong chat window
if(activeChat['receiver'] && ( activeChat['receiver'] === floID || activeChat['receiver'] === groupID)){ if(activeChat['floID'] && ( activeChat['floID'] === floID || activeChat['floID'] === groupID)){
if(updateChatCard && activeChat.isGroup && message && sender === myFloID) return if(updateChatCard && activeChat.isGroup && message && sender === myFloID) return
frag.append(render.messageBubble({...messages[i], updateChatCard})) frag.append(render.messageBubble({...messages[i], updateChatCard}))
} }
@ -2356,7 +2370,7 @@
chatCard.querySelector('.last-message').textContent = finalMessage chatCard.querySelector('.last-message').textContent = finalMessage
chatCard.querySelector('.time').textContent = getFormatedTime(time, true) chatCard.querySelector('.time').textContent = getFormatedTime(time, true)
if(activeChat.receiver === (floID || groupID)){ if(activeChat.floID === (floID || groupID)){
if(chatScrollInfo.isScrolledUp) if(chatScrollInfo.isScrolledUp)
getRef('scroll_to_bottom').classList.add('new-message') getRef('scroll_to_bottom').classList.add('new-message')
else{ else{
@ -2426,7 +2440,7 @@
textColor = contact.getAttribute('text-color'), textColor = contact.getAttribute('text-color'),
backgroundColor = contact.getAttribute('background-color') backgroundColor = contact.getAttribute('background-color')
activeChat['receiver'] = floID activeChat['floID'] = floID
getRef("chat_flo_id").textContent = floID getRef("chat_flo_id").textContent = floID
activeChat['isGroup'] = floGlobals.groups[floID] ? true : false activeChat['isGroup'] = floGlobals.groups[floID] ? true : false
if(activeChat.isGroup){ if(activeChat.isGroup){
@ -2451,7 +2465,7 @@
getRef("group_description_card").classList.remove('hide-completely') getRef("group_description_card").classList.remove('hide-completely')
getRef("group_members_card").classList.remove('hide-completely') getRef("group_members_card").classList.remove('hide-completely')
getRef("group_description").textContent = floGlobals.groups[floID].description; getRef("group_description").value = floGlobals.groups[floID].description;
} }
else{ else{
getRef("receiver_initial").textContent = getContactName(floID).charAt(0); getRef("receiver_initial").textContent = getContactName(floID).charAt(0);
@ -2679,40 +2693,61 @@
getRef('navbar_backdrop').classList.toggle('hide') getRef('navbar_backdrop').classList.toggle('hide')
} }
function setNameEditable() {
if (!getRef('contact_name').isContentEditable) { document.addEventListener('contentchanged', e => {
getRef('contact_name').contentEditable = 'true' if (e.target.closest('#contact_name')) {
getRef('contact_name').focus() changeContactName(e.detail.value.trim())
document.execCommand('selectAll', false, null);
clickedContact['name'] = getRef('contact_name').textContent
} }
} else if(e.target.closest('#group_description')){
messenger.changeGroupDescription(activeChat.floID, e.detail.value.trim())
async function changeContactName() { .then(res => {
clickedContact['name'] = getRef('contact_name').textContent.trim() notify('Changed group description', 'success')
if (clickedContact['name'] === '')
clickedContact['name'] = 'Unknown'
messenger.storeContact(clickedContact['floID'], clickedContact['name']).then(result => {
getRef('contact_initial').textContent = clickedContact['name'].charAt(0)
document.querySelectorAll(`.contact[flo-id="${clickedContact['floID']}"]`).forEach(contact => {
contact.children[0].textContent = clickedContact['name'].charAt(0)
contact.children[1].textContent = clickedContact['name']
contact.setAttribute('name', clickedContact['name'])
}) })
notify('Renamed contact', 'success') .catch(error => notify(error, "error"));
})
.catch(error => notify(error, "error"));
}
document.getElementById('contact_details_popup').addEventListener('click', e => {
if (!e.target.closest('#contact_name') && !e.target.closest('#edit_contact_name')) {
if (getRef('contact_name').isContentEditable)
getRef('contact_name').contentEditable = 'false'
if (clickedContact['name'] !== getRef('contact_name').textContent)
changeContactName()
} }
}) })
async function changeContactName(name) {
clickedContact['name'] = name
if (clickedContact['name'] === '')
clickedContact['name'] = 'Unknown'
if(clickedContact.isGroup){
messenger.changeGroupName(clickedContact.floID, name).then(res => {
updatechatCards({isGroup: true})
notify('Changed group name', 'success')
})
.catch(error => notify(error, "error"));
}
else{
messenger.storeContact(clickedContact['floID'], clickedContact['name']).then(result => {
updatechatCards({isGroup: false})
notify('Changed contact name', 'success')
})
.catch(error => notify(error, "error"));
}
}
function updatechatCards({isGroup = false}){
if(activeChat.floID && activeChat.floID === clickedContact.floID){
getRef('receiver_name').textContent = clickedContact['name']
getRef('chat_name').textContent = clickedContact['name']
}
if(!isGroup){
getRef('contact_initial').textContent = clickedContact['name'].charAt(0)
if(activeChat.floID && activeChat.floID === clickedContact.floID){
getRef('receiver_initial').textContent = clickedContact['name'].charAt(0)
getRef('chat_dp').textContent = clickedContact['name'].charAt(0)
}
}
document.querySelectorAll(`.contact[flo-id="${clickedContact['floID']}"]`).forEach(contact => {
if(!isGroup){
contact.children[0].textContent = clickedContact['name'].charAt(0)
contact.children[1].textContent = clickedContact['name']
}
contact.setAttribute('name', clickedContact['name'])
})
}
function toggleSearch(target){ function toggleSearch(target){
getRef(target).classList.toggle('expand') getRef(target).classList.toggle('expand')
if(getRef(target).classList.contains('expand')) if(getRef(target).classList.contains('expand'))
@ -2722,6 +2757,7 @@
let isChatDetailsOpen = false let isChatDetailsOpen = false
function showChatDetails({show, animate= true}){ function showChatDetails({show, animate= true}){
if(show){ if(show){
if(isChatDetailsOpen) return
isChatDetailsOpen = true isChatDetailsOpen = true
getRef('chat').classList.add('expand-side-panel') getRef('chat').classList.add('expand-side-panel')
getRef('chat_left').classList.add('hide-on-medium') getRef('chat_left').classList.add('hide-on-medium')

View File

@ -253,9 +253,6 @@ border: none;
.readonly{ .readonly{
pointer-events: none; pointer-events: none;
} }
input:focus{
caret-color: var(--accent-color);
}
.input:focus-within:not(.readonly){ .input:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color) inset !important; box-shadow: 0 0 0 0.1rem var(--accent-color) inset !important;
} }
@ -623,9 +620,6 @@ textarea{
.readonly{ .readonly{
pointer-events: none; pointer-events: none;
} }
textarea:focus{
caret-color: var(--accent-color);
}
.textarea:focus-within:not(.readonly){ .textarea:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color) inset; box-shadow: 0 0 0 0.1rem var(--accent-color) inset;
} }
@ -2037,15 +2031,17 @@ customElements.define('sm-popup', class extends HTMLElement {
}) })
}, 300); }, 300);
} }
this.dispatchEvent( setTimeout(() => {
new CustomEvent("popupclosed", { this.dispatchEvent(
bubbles: true, new CustomEvent("popupclosed", {
detail: { bubbles: true,
popup: this, detail: {
popupStack: this.popupStack popup: this,
} popupStack: this.popupStack
}) }
) })
)
}, 300);
} }
handleTouchStart = (e) => { handleTouchStart = (e) => {
@ -3502,4 +3498,229 @@ customElements.define('sm-section', class extends HTMLElement {
mode: 'open' mode: 'open'
}).append(section.content.cloneNode(true)) }).append(section.content.cloneNode(true))
} }
})
const textField = document.createElement('template')
textField.innerHTML = `
<style>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
.text-field{
display: flex;
align-items: center;
}
.text{
padding: 0.6rem 0;
transition: background-color 0.3s;
border-bottom: 0.15rem solid transparent;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-all;
word-break: break-word;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
.text:focus{
outline: none;
border-bottom: 0.15rem solid var(--accent-color);
}
.text:focus-visible{
outline: none;
background: solid rgba(var(--text-color), 0.06);
}
.editable{
border-bottom: 0.15rem solid rgba(var(--text-color), 0.6);
}
.icon-container{
position: relative;
margin-left: 0.5rem;
height: 1.8rem;
width: 1.8rem;
}
.icon{
position: absolute;
cursor: pointer;
fill: none;
stroke-width: 6;
stroke: rgba(var(--text-color), 1);
height: 1.8rem;
width: 1.8rem;
padding: 0.4rem;
overflow: visible;
stroke-linecap: round;
stroke-linejoin: round;
}
.hide{
display: none;
}
</style>
<div class="text-field">
<div class="text" part="text"></div>
<div class="icon-container">
<svg class="edit-button icon" viewBox="0 0 64 64">
<title>Edit</title>
<path d="M46.73,14.81l7,7,7.65-7.6A7.15,7.15,0,0,0,61.39,4L60.11,2.77a7.23,7.23,0,0,0-10.19,0L3.87,48.57a5,5,0,0,0-1.39,2.6L.53,61.27a1.74,1.74,0,0,0,2,2l10.15-1.94A5.06,5.06,0,0,0,15.34,60L49.6,25.9"/>
</svg>
<svg class="save-button icon hide" viewBox="0 0 64 64">
<title>Save</title>
<polyline points="0.35 31.82 21.45 52.98 63.65 10.66"/>
</svg>
</div>
</div>
`
customElements.define('text-field', class extends HTMLElement{
constructor(){
super()
this.attachShadow({
mode: 'open'
}).append(textField.content.cloneNode(true))
this.textField = this.shadowRoot.querySelector('.text-field')
this.textContainer = this.textField.children[0]
this.iconsContainer = this.textField.children[1]
this.editButton = this.textField.querySelector('.edit-button')
this.saveButton = this.textField.querySelector('.save-button')
this.isTextEditable = false
this.isDisabled = false
}
static get observedAttributes(){
return ['disable']
}
get value(){
return this.text
}
set value(val) {
this.text = val
this.textContainer.textContent = val
this.setAttribute('value', val)
}
set disabled(val) {
this.isDisabled = val
if(this.isDisabled)
this.setAttribute('disable', '')
else
this.removeAttribute('disable')
}
fireEvent = (value) => {
let event = new CustomEvent('contentchanged', {
bubbles: true,
cancelable: true,
composed: true,
detail: {
value
}
});
this.dispatchEvent(event);
}
setEditable = () => {
if(this.isTextEditable) return
this.textContainer.contentEditable = true
this.textContainer.classList.add('editable')
this.textContainer.focus()
document.execCommand('selectAll', false, null);
this.editButton.animate(this.rotateOut, this.animOptions).onfinish = () => {
this.editButton.classList.add('hide')
}
setTimeout(() => {
this.saveButton.classList.remove('hide')
this.saveButton.animate(this.rotateIn, this.animOptions)
}, 100);
this.isTextEditable = true
}
setNonEditable = () => {
if (!this.isTextEditable) return
this.textContainer.contentEditable = false
this.textContainer.classList.remove('editable')
if (this.text !== this.textContainer.textContent.trim()) {
this.setAttribute('value', this.textContainer.textContent)
this.text = this.textContainer.textContent.trim()
this.fireEvent(this.text)
}
this.saveButton.animate(this.rotateOut, this.animOptions).onfinish = () => {
this.saveButton.classList.add('hide')
}
setTimeout(() => {
this.editButton.classList.remove('hide')
this.editButton.animate(this.rotateIn, this.animOptions)
}, 100);
this.isTextEditable = false
}
revert = () => {
if (this.textContainer.isContentEditable) {
this.value = this.text
this.setNonEditable()
}
}
connectedCallback(){
this.text
if(this.hasAttribute('disable'))
this.isDisabled = true
else
this.isDisabled = false
this.rotateOut = [
{
transform: 'rotate(0)',
opacity: 1
},
{
transform: 'rotate(90deg)',
opacity: 0
},
]
this.rotateIn = [
{
transform: 'rotate(-90deg)',
opacity: 0
},
{
transform: 'rotate(0)',
opacity: 1
},
]
this.animOptions = {
duration: 300,
easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
fill: 'forwards'
}
if (!this.isDisabled) {
this.iconsContainer.classList.remove('hide')
this.textContainer.addEventListener('dblclick', this.setEditable)
this.editButton.addEventListener('click', this.setEditable)
this.saveButton.addEventListener('click', this.setNonEditable)
}
}
attributeChangedCallback(name) {
if (name === 'disable') {
if (this.hasAttribute('disable')) {
this.iconsContainer.classList.add('hide')
this.textContainer.removeEventListener('dblclick', this.setEditable)
this.editButton.removeEventListener('click', this.setEditable)
this.saveButton.removeEventListener('click', this.setNonEditable)
this.revert()
}
else {
this.iconsContainer.classList.remove('hide')
this.textContainer.addEventListener('dblclick', this.setEditable)
this.editButton.addEventListener('click', this.setEditable)
this.saveButton.addEventListener('click', this.setNonEditable)
}
}
}
disconnectedCallback() {
this.textContainer.removeEventListener('dblclick', this.setEditable)
this.editButton.removeEventListener('click', this.setEditable)
this.saveButton.removeEventListener('click', this.setNonEditable)
}
}) })