From 18c30de1212e0151ed557f69f6b9f7899565a9df Mon Sep 17 00:00:00 2001 From: sairaj mote Date: Sun, 24 Jan 2021 19:00:19 +0530 Subject: [PATCH] usability improvements --- css/main.css | 418 ++++++++++++++-------- css/main.min.css | 2 +- css/main.scss | 415 ++++++++++++++-------- index.html | 788 +++++++++++++++++++++++++----------------- scripts/components.js | 3 +- 5 files changed, 1021 insertions(+), 605 deletions(-) diff --git a/css/main.css b/css/main.css index 72d62f0..82c642a 100644 --- a/css/main.css +++ b/css/main.css @@ -570,6 +570,7 @@ sm-button[variant=primary] .icon { box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.06); border-radius: 2rem; text-transform: uppercase; + user-select: none; } .group-icon { @@ -650,6 +651,9 @@ sm-button[variant=primary] .icon { #contact_details_popup .copy-row h4 { font-weight: 400; } +#contact_details_popup .group-icon { + padding: 0.2rem !important; +} #contact_details_popup #contact_initial { height: 3.6rem; width: 3.6rem; @@ -668,7 +672,7 @@ sm-button[variant=primary] .icon { background: rgba(var(--text-color), 0.1); } -#warn_no_encryption, .date-card { +#warn_no_encryption, .date-card, .group-event-card { padding: 0.4rem 0.8rem; background: rgba(var(--text-color), 0.1); font-weight: 500; @@ -677,6 +681,12 @@ sm-button[variant=primary] .icon { margin: 1rem 0; justify-self: center; align-self: center; + text-align: center; +} + +.group-event-card { + font-size: 0.8rem; + font-weight: 400; } #warn_no_encryption { @@ -962,8 +972,10 @@ sm-button[variant=primary] .icon { #selected_contacts_container { display: grid; - grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(3rem, 1fr)); gap: 1rem; + max-height: 8rem; + overflow-y: auto; } #contacts, #mails { @@ -1009,7 +1021,7 @@ sm-button[variant=primary] .icon { width: 0.9rem; } #contacts .header sm-input::part(input), #mails .header sm-input::part(input), #settings_page .header sm-input::part(input) { - border-radius: 3rem; + border-radius: 0.5rem; padding: 0.2rem 0.8rem; } #contacts .header h4, #mails .header h4, #settings_page .header h4 { @@ -1052,114 +1064,101 @@ sm-button[variant=primary] .icon { overflow-y: hidden; } -#chat { +#chat_left, +#chat_details_panel { + position: relative; + display: flex; + flex-direction: column; height: 100%; + overflow-y: auto; } -#chat header { + +#chat_details_panel { + background: rgba(var(--text-color), 0.04); + padding-bottom: 1.5rem; +} +#chat_details_panel .card { + margin: 0 1rem; + padding: 1.5rem 1rem; + border-radius: 0.8rem; + background: rgba(var(--text-color), 0.04); +} +#chat_details_panel .card:not(:last-of-type) { + margin-bottom: 1rem; +} +#chat_details_panel .card > h4 { + font-weight: 400; + font-size: 0.9rem; + color: rgba(var(--text-color), 0.8); + margin-bottom: 0.5rem; +} +#chat_details_panel header { padding: 1rem; min-height: 4rem; - grid-template-columns: auto 1fr auto; } -#chat header .back-button { - padding: 0.1rem; - stroke-width: 8; - margin-right: 0.5rem; - stroke: rgba(var(--text-color), 0.8); -} -#chat header .initial { +#chat_details_panel header .icon { + height: 2.3rem; + width: 2.3rem; + padding: 0.7rem; cursor: pointer; - margin-right: 1rem; - height: 2.2rem; - width: 2.2rem; - flex-shrink: 0; } -#chat header h4 { +#chat_details_panel .contact { + padding: 0.5rem 0; +} +#chat_details_panel #chat_profile { + display: grid; + place-items: center; + margin-top: 1.5rem; + padding-bottom: 1.5rem; +} +#chat_details_panel #chat_profile .initial { + margin-top: -5.5rem; + margin-bottom: 1rem; + height: 8rem; + width: 8rem; + border-radius: 50%; + font-size: 4rem; +} +#chat_details_panel #chat_profile .initial .icon { + height: 4rem; + width: 4rem; +} +#chat_details_panel #chat_profile #chat_name { font-weight: 500; + font-size: 1.2rem; +} +#chat_details_panel #chat_profile #last_interaction_time { + color: rgba(var(--text-color), 0.7); font-size: 0.9rem; + margin-top: 0.5rem; } -#chat header #receiver_name { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; +#chat_details_panel .copy { + font-weight: 400; } -#chat #scroll_to_bottom { - position: fixed; - right: 0; - bottom: 4rem; - width: 2.6rem; - height: 2.6rem; - padding: 0.9rem; - border-radius: 4rem; - z-index: 1; - margin: 1.5rem; - stroke-width: 8; - cursor: pointer; - transform: scale(0); - transition: transform 0.3s; -} -#chat footer #emoji_toggle { - align-self: center; - padding: 0.6rem; - width: 2.6rem; - height: 2.6rem; - border-radius: 2rem; - cursor: pointer; -} -#chat footer #emoji_toggle path { - fill: rgba(var(--text-color), 0.5); -} -#chat footer #emoji_toggle.active path { - fill: var(--accent-color); -} -#chat footer .flex { - align-items: flex-end; - padding: 1rem 1rem 1rem 0.4rem; -} -#chat footer sm-textarea::part(textarea) { - background: rgba(var(--text-color), 0.1); - padding-right: 3rem; - border-radius: 2rem; -} -#chat #send_message_button { - position: absolute; - right: 1.5rem; - transform: scale(0); - opacity: 0; - pointer-events: none; - z-index: 1; - align-self: center; - height: 2.4rem; - width: 2.4rem; - padding: 0.5rem; - cursor: pointer; - stroke: none; - fill: rgba(var(--text-color), 0.4); - margin-left: 1rem; - transition: 0.3s; -} -#chat #send_message_button.active { - opacity: 1; - fill: var(--accent-color); - transform: none; - pointer-events: all; -} -#chat #type_message { - margin: 0; + +#chat { + position: relative; + grid-template-columns: 1fr; } #chat .message { position: relative; - display: grid; - align-items: center; - gap: 0.2rem; - width: 100%; + display: flex; + flex-direction: column; + width: auto; font-size: 0.92rem; max-width: max-content; margin-bottom: 0.2rem; margin-top: 0.8rem; padding: 0.6em 1em; + transition: opacity 0.3s, transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); +} +#chat .message .sender-name { + font-size: 0.85rem; + font-weight: 500; + margin-bottom: 0.3rem; } #chat .message .message-body { - display: inline-flex; + display: flex; align-items: center; flex-wrap: wrap; overflow-wrap: break-word; @@ -1170,7 +1169,7 @@ sm-button[variant=primary] .icon { -webkit-hyphens: auto; hyphens: auto; white-space: pre-wrap; - line-height: 1.6; + line-height: 1.5; } #chat .message .message-body a { color: inherit; @@ -1184,12 +1183,16 @@ sm-button[variant=primary] .icon { white-space: nowrap; font-size: 0.8em; opacity: 0.8; + justify-self: flex-end; + padding-left: 1rem; + align-self: flex-end; + margin-top: 0.2rem; } #chat .sent { margin-left: auto; + color: #efefef; background: var(--accent-color); - color: #f0f0f0; - border-radius: 1em 0 1em 1em; + border-radius: 0.8rem 0 0.8rem 0.8rem; } #chat .sent::after { content: ""; @@ -1202,12 +1205,9 @@ sm-button[variant=primary] .icon { border-width: 0.5em 0.3em 0 0; border-color: var(--accent-color) transparent transparent transparent; } -#chat .sent .time { - margin-left: auto; -} #chat .received { background: rgba(var(--text-color), 0.1); - border-radius: 0 1em 1em 1em; + border-radius: 0 0.8rem 0.8rem 0.8rem; } #chat .received::after { content: ""; @@ -1230,31 +1230,144 @@ sm-button[variant=primary] .icon { } #chat .sent + .sent, #chat .received + .received { - border-radius: 1em; + border-radius: 0.8rem; } #chat .unconfirmed { opacity: 0.7; - transform-origin: right; - animation: slide-up 0.3s forwards; + transform-origin: left; + animation: pop 0.3s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); } -@keyframes slide-up { - from { - transform: translateY(-2rem); +@keyframes pop { + 0% { + transform: rotate(5deg) translate(-0.5rem, 1rem); } - to { - transform: none; + 100% { + transform: rotate(0) translate(0, 0); } } +#chat_header { + padding: 1rem; + min-height: 4rem; + grid-template-columns: auto 1fr auto; +} +#chat_header .back-button { + height: 2rem; + width: 2rem; + padding: 0.5rem; + stroke-width: 8; + margin-right: 0.5rem; + stroke: rgba(var(--text-color), 0.8); +} +#chat_header .initial { + cursor: pointer; + margin-right: 1rem; + height: 2.2rem; + width: 2.2rem; + flex-shrink: 0; +} +#chat_header #receiver_name { + font-weight: 500; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +#scroll_to_bottom { + position: absolute; + display: flex; + right: 0; + bottom: 4rem; + border-radius: 4rem; + z-index: 1; + aspect-ratio: 1/1; + margin: 1.5rem; + cursor: pointer; + transform: scale(0); + transition: transform 0.3s; +} +#scroll_to_bottom.new-message::after { + position: absolute; + content: ""; + top: 0; + right: 0; + z-index: 2; + padding: 0.5rem; + border-radius: 50%; + background: #00E676; +} +#scroll_to_bottom .icon { + width: 2.6rem; + height: 2.6rem; + padding: 0.9rem; + stroke-width: 8; +} + +#chat_footer #emoji_toggle { + align-self: center; + padding: 0.6rem; + margin-right: 0.5rem; + width: 2.6rem; + height: 2.6rem; + border-radius: 2rem; + cursor: pointer; +} +#chat_footer #emoji_toggle path { + fill: rgba(var(--text-color), 0.5); +} +#chat_footer #emoji_toggle.active path { + fill: var(--accent-color); +} +#chat_footer .flex { + align-items: flex-end; + padding: 1rem 1rem 1rem 0.4rem; +} +#chat_footer sm-textarea::part(textarea) { + padding-right: 3rem; + border-radius: 0.5rem; +} + +#send_message_button { + position: absolute; + right: 1.5rem; + transform: scale(0); + opacity: 0; + pointer-events: none; + z-index: 1; + align-self: center; + height: 2.4rem; + width: 2.4rem; + padding: 0.5rem; + cursor: pointer; + stroke: none; + fill: rgba(var(--text-color), 0.4); + margin-left: 1rem; + transition: 0.3s; +} +#send_message_button.active { + opacity: 1; + fill: var(--accent-color); + transform: none; + pointer-events: all; +} + +#type_message { + margin: 0; +} + .big-emoji .message-body { font-size: 2.6rem; } -#messages_container { +#chat_middle { flex: 1; padding: 0 1rem; } +#messages_container { + height: 100%; +} + #emoji_picker { display: grid; gap: 1rem; @@ -1279,6 +1392,7 @@ sm-button[variant=primary] .icon { background: linear-gradient(rgba(var(--text-color), 0.06), rgba(var(--text-color), 0.06)), rgba(var(--foreground-color), 1); padding: 1rem 0; z-index: 1; + user-select: none; } .emoji { @@ -1313,7 +1427,7 @@ sm-button[variant=primary] .icon { stroke: rgba(var(--text-color), 0.4); } -#messages_container, +#chat_middle, #chat_container, #inbox_mail_container, #sent_mail_container, @@ -1480,7 +1594,7 @@ sm-panel { } #main_navbar { - transform: translateX(-100%); + transform: translateX(-110%); transition: transform 0.3s; z-index: 4; box-shadow: 0 0 1rem rgba(0, 0, 0, 0.3); @@ -1522,18 +1636,6 @@ sm-panel { } } @media only screen and (min-width: 640px) { - ::-webkit-scrollbar { - width: 0.5rem; - } - - ::-webkit-scrollbar-thumb { - background: rgba(var(--text-color), 0.3); - border-radius: 1rem; - } - ::-webkit-scrollbar-thumb:hover { - background: rgba(var(--text-color), 0.5); - } - .hide-on-desktop { display: none !important; } @@ -1575,11 +1677,13 @@ sm-panel { width: auto; padding-bottom: 0.5rem; background: rgba(var(--text-color), 0.06); + margin: 0.5rem; + border-radius: 0.8rem; } #main_navbar .logo-section { display: flex; justify-content: center; - margin: 1.5rem 0; + margin: 1rem 0 2rem 0; } #main_navbar .logo-section .main-logo { margin: 0; @@ -1614,20 +1718,19 @@ sm-panel { max-height: 18rem; } - #chat .message .message-body { - max-width: 65ch; + #chat .message { + width: auto; + align-self: flex-start; + max-width: 55ch; } #chat_page, #mail_page { grid-template-columns: 20rem 1fr; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); - z-index: 1; } #settings_page { display: grid; height: 100vh; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); grid-template-columns: 14rem 1fr; } #settings_page sm-button { @@ -1655,6 +1758,16 @@ sm-panel { max-height: 100vh; } } +@media only screen and (max-width: 1280px) { + .hide-on-medium { + display: none !important; + } +} +@media only screen and (min-width: 1080px) { + #chat #messages_container { + padding: 1rem 5rem; + } +} @media only screen and (min-width: 1280px) { #landing { gap: 4vw; @@ -1668,31 +1781,62 @@ sm-panel { grid-template-columns: 21rem 1fr; } - #chat header { - padding: 0.8rem 1.5rem; + #chat_details_panel { + position: relative; } - #chat #messages_container { - padding: 1rem 5rem; + + #chat.expand-side-panel { + grid-template-columns: 1fr 24rem; + } + #chat.expand-side-panel #messages_container { + padding: 1rem; + } + #chat .active { + background: rgba(var(--text-color), 0.1); + } + + .contact.active, +.mail-card.active { + background: rgba(var(--text-color), 0.06); + } + + .card { + display: inline-flex; + width: auto; + } + + #settings_panel { + overflow-y: auto; + max-height: 100vh; } } @media (hover: hover) { - .contact:hover, .mail-card:hover, .navbar-item:hover { - background: rgba(var(--text-color), 0.06); - cursor: pointer; + ::-webkit-scrollbar { + width: 0.5rem; } + ::-webkit-scrollbar-thumb { + background: rgba(var(--text-color), 0.3); + border-radius: 1rem; + } + ::-webkit-scrollbar-thumb:hover { + background: rgba(var(--text-color), 0.5); + } + + .contact { + cursor: pointer; + } .contact .menu { opacity: 0; transition: opacity 0.3s; } + .contact:hover { + background: rgba(var(--text-color), 0.06); + } .contact:hover .menu { opacity: 1; } - - .emoji:hover { - background: rgba(var(--text-color), 0.1); - } } @media (hover: none) { .contact .menu { diff --git a/css/main.min.css b/css/main.min.css index 496ebdd..7eae98a 100644 --- a/css/main.min.css +++ b/css/main.min.css @@ -1 +1 @@ -#landing_page,.sign-in-box,body,body #scroll_to_bottom{background:rgba(var(--foreground-color),1)}.align-center,.popup-header{align-items:center}#chat header #receiver_name,.contact .last-message,.contact .name,.copy-row .copy,.mail-card .sender,.text-overflow{text-overflow:ellipsis;white-space:nowrap}*,::after,::before{padding:0;margin:0;box-sizing:border-box;font-family:Roboto,sans-serif}:root{scroll-behavior:smooth;font-size:clamp(1rem,1.2vmax,3rem)}body,html{height:100%}body{--accent-color:#5b00d3;--secondary-color:#ffac2e;--text-color:17,17,17;--text-color-light:100,100,100;--foreground-color:255,255,255;--background-color:#efefef;--error-color:red;color:rgba(var(--text-color),1)}body #scroll_to_bottom{box-shadow:0 .3rem .4rem rgba(0,0,0,.2)}body[data-theme=dark]{--accent-color:#923eff;--secondary-color:#d60739;--text-color:240,240,240;--text-color-light:170,170,170;--foreground-color:20,20,20}body[data-theme=dark] .initial{color:rgba(var(--text-color),1)!important;box-shadow:0 .1rem .1rem rgba(0,0,0,.16)}body[data-theme=dark] .message,h1,h2,h3,h4,h5,textarea{color:rgba(var(--text-color),1)}body[data-theme=dark] #scroll_to_bottom{background:linear-gradient(rgba(var(--text-color),.1),rgba(var(--text-color),.1)),rgba(var(--foreground-color),1);box-shadow:0 .4rem .4rem rgba(0,0,0,.3)}p{line-height:1.6}h1{font-size:3rem}h2{font-size:2rem}h3{font-size:1.5rem}h4{font-size:1.1rem}h5{font-size:.8rem}h1,h2,h3,h4,h5{font-weight:600}a:any-link,strong{font-weight:500}textarea{background:rgba(var(--text-color),.06);border:none;border-radius:.3rem;width:100%;padding:1rem;font-size:1rem;resize:none;line-height:1.6}textarea:focus{outline:0;box-shadow:0 0 0 .1rem var(--accent-color)}.flex{display:flex}.grid{display:grid}.grid-2{grid-template-columns:auto auto;gap:1em}.justify-right{margin-left:auto}.direction-column{flex-direction:column}.rest{flex:1}.hide{opacity:0;pointer-events:none}.hide-completely{display:none!important}.no-transformations{transform:none!important}.breakable{overflow-wrap:break-word}.text-overflow{overflow:hidden}.sticky{position:sticky;top:1rem}.light-text{color:rgba(var(--text-color-light),1)}.accent-color{color:var(--accent-color)}.secondary-color{color:var(--secondary-color)}.fab{filter:drop-shadow(0 .4rem .3rem rgba(0, 0, 0, .2));margin:1.5rem;position:fixed;right:0;bottom:0;z-index:1}.fab::part(button){padding:.9rem 1.6rem}.fab .icon{margin-left:0!important;margin-right:.5rem;height:.9rem!important;stroke-width:8!important}a:any-link{word-wrap:break-word;color:var(--accent-color)}.solid-background{background:var(--background-color)!important}.normal-weight{font-weight:400}.icon{fill:none;stroke-width:6;stroke:rgba(var(--text-color),1);height:1.2rem;width:1.2rem;overflow:visible;stroke-linecap:round;stroke-linejoin:round}span.ripple{position:absolute;border-radius:50%;transform:scale(0);background:rgba(var(--text-color),.2);pointer-events:none}#landing_illustration,.contact,.initial,.interact,.logo-section{position:relative}.interact{overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}sm-popup sm-input+sm-input{margin-top:1rem}.popup-header{padding:.5rem 1.5rem 0;display:flex;width:100%}.popup-header .icon{padding:.7rem;height:2.4rem;width:2.4rem;stroke-width:8;transform:translateX(-.5rem);cursor:pointer;-webkit-tap-highlight-color:transparent}.popup-header .back{transform:none}.popup-header button,.popup-header sm-button{width:auto;margin-left:auto}.copy-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.5rem;width:auto}.copy-row .icon{cursor:pointer;padding:.4rem;height:1.8rem;width:1.8rem}.copy-row .copy{overflow:hidden}.copy-row h4{margin-bottom:0!important}#confirmation_popup,#prompt_popup{flex-direction:column}#confirmation_popup h4,#prompt_popup h4{font-weight:500;margin-bottom:.5rem}#confirmation_popup sm-button,#prompt_popup sm-button{margin:0}#confirmation_popup .flex,#prompt_popup .flex{padding:0;margin-top:2rem}#confirmation_popup .flex sm-button:first-of-type,#prompt_popup .flex sm-button:first-of-type{margin-right:.6rem;margin-left:auto}.card,sm-button{margin:1rem 0}.page{align-items:flex-start;width:100%;height:100%}.card{display:flex;flex-direction:column}sm-button .icon{margin-right:.4rem}sm-button[variant=primary]{--foreground-color:255,255,255}sm-button[variant=primary] .icon{align-self:center;height:1rem;width:1rem;margin-left:.8rem;stroke-width:6;stroke:#fff}.logo-section{align-items:center;height:max-content;margin:.5rem 0}.logo-section h5{font-size:1.1rem!important;font-weight:500}.logo-section .main-logo{height:1.4rem;margin-right:.4rem;fill:rgba(var(--text-color),1);stroke:none}.logo-section img{width:2rem;margin-right:.5rem}.select-file input[type=file]{display:none}#landing{display:grid;border-radius:.6rem;width:100%;padding:0 1.5rem;height:100%;align-items:center;overflow-y:auto}#landing .logo-section{padding:1.5rem;display:flex}#landing .title-font{line-height:1.2;font-weight:700;font-size:2.5rem}#landing .left{display:grid;flex-direction:column;padding-bottom:1.5rem;z-index:1}#landing .left h4{color:rgba(var(--foreground-color),1);font-weight:500}#landing .left p,.contact .last-message,.contact .name{color:rgba(var(--text-color),.8)}#landing .left sm-button{margin:1.5rem 0 2rem;width:max-content}#landing_illustration,.sign-in-box,.sign-in-box form,.sign-in-box sm-button,.sign-in-box sm-panel{width:100%}#landing .left h3{margin-bottom:1rem;font-weight:500}#landing .left p{margin-top:1rem;font-size:1.1rem}.logo-section{padding:1.5rem}#sign_in_popup::part(popup-body){padding:0}.sign-in-box{margin:0 -2rem;z-index:1;justify-self:center;padding:1.5rem;border-radius:.5rem}.sign-in-box sm-input{margin-top:1.5rem}.sign-in-box sm-tab-header{margin:0;background:0 0;align-self:flex-start}.sign-in-box sm-tab-header::part(tab-header){padding-bottom:.4rem;gap:1.5rem}.sign-in-box sm-tab::part(tab){padding:.4rem 0}.sign-in-box sm-tab-panels{margin-top:1.5rem}.sign-in-box h2{margin-bottom:.5rem}.sign-in-box h3{font-weight:500}.sign-in-box h4{font-weight:500;margin-bottom:1.5rem}.sign-in-box h5{opacity:.8;font-weight:500}.sign-in-box strong{display:flex;background:#ffd92e;padding:.4em .6em;border-radius:.4em;color:#111;margin-top:.5rem}.sign-in-box .copy-row h4{max-width:34ch}.sign-in-box .copy-row:not(:last-of-type){margin-bottom:1rem}.sign-in-box button{margin-top:2rem;padding:.6rem 1.6rem}.sign-in-box sm-button::part(button){padding:.8rem 1.6rem}.sign-in-box p{margin-bottom:.5rem;max-width:35ch;margin-top:.5rem}.sign-in-box #credentials_section{border-top:1px rgba(var(--text-color),.2) solid;margin-top:1rem;padding-top:1.5rem;animation:slide-down .3s forwards}.sign-in-box #sign_in_with,.sign-in-box sm-button{margin-top:2rem;margin-bottom:0}@keyframes slide-down{from{transform:translateY(-1rem)}to{transform:none}}#loading_page{height:100vh;display:grid;place-content:center;justify-items:center}#loading_page svg{z-index:1;transform-origin:bottom;height:6rem;width:6rem;animation:bounce .5s infinite alternate ease-in}#loading_page .shadow{margin-top:-1rem;width:5rem;height:2rem;background:rgba(var(--text-color),.1);border-radius:50%;animation:scale .5s infinite alternate ease-in;margin-left:1rem}#loading_page h4{margin-top:2rem}@keyframes bounce{0%{transform:scaleY(1) translateY(-4rem)}90%{transform:scaleY(1) translateY(0)}100%{transform:scaleY(.8)}}@keyframes scale{0%{transform:scale(.5)}90%{transform:scale(1.05)}100%{transform:scale(1)}}.initial{justify-content:center;font-size:1.2rem;width:2.5rem;height:2.5rem;color:#fff;box-shadow:0 .1rem .1rem rgba(0,0,0,.06);border-radius:2rem;text-transform:uppercase}.group-icon{height:1.6rem;width:1.6rem;fill:#fff;stroke:none}.contact{display:grid;gap:0 1rem;padding:.8rem 1.5rem;align-items:center;flex-shrink:0;overflow:hidden}.contact:not(.chat){grid-template-columns:auto 1fr;grid-template-areas:"dp ."}.contact.chat,.contact.group{grid-template-columns:auto 1fr auto;grid-template-areas:"dp . time" "dp . menu"}.contact .initial{grid-area:dp}.contact .name{font-size:1em;font-weight:500;overflow:hidden}.contact .last-message{overflow:hidden;font-weight:400;font-size:.9em}.contact .menu{grid-area:menu;justify-self:flex-end;padding:.2rem;fill:rgba(var(--text-color),1)}.contact .time{font-weight:500;color:rgba(var(--text-color),.7);grid-area:time}#contact_details_popup>.flex:first-of-type{margin:1rem 0}#contact_details_popup>.flex:first-of-type .flex .icon{height:2.6rem;width:2.6rem;padding:.85rem;cursor:pointer;stroke-width:8}#contact_details_popup>.flex:first-of-type .flex .icon:hover{background:rgba(var(--text-color),.06)}#contact_details_popup h5{font-weight:500;opacity:.8}#contact_details_popup .copy-row{margin-bottom:1.5rem}#contact_details_popup .copy-row h4{font-weight:400}#contact_details_popup #contact_initial{height:3.6rem;width:3.6rem;font-size:1.6rem;border-radius:4rem;margin-bottom:1rem}#contact_details_popup #contact_name{border-radius:.5rem;max-width:30ch;padding:.6rem 1.2rem;overflow-wrap:break-word}#contact_details_popup #contact_name:focus{outline:0;background:rgba(var(--text-color),.1)}#warn_no_encryption,.date-card{padding:.4rem .8rem;background:rgba(var(--text-color),.1);font-weight:500;border-radius:.5rem;color:rgba(var(--text-color),.8);margin:1rem 0;justify-self:center;align-self:center}#warn_no_encryption{background:#fffd8d;color:#111}.mail-card.unread::before{content:"";position:absolute;padding:.4rem;border-radius:1rem;top:0;left:0;background:var(--accent-color)}.contact .initial::after{content:"";position:absolute;height:calc(100% + .8rem);width:calc(100% + .8rem);border:var(--accent-color) solid;border-radius:100%;transform:scale(.8);opacity:0;transition:transform .3s,opacity .3s}.mail,.mail-card{position:relative}.contact.unread .initial::after{transform:scale(1);opacity:1}.contact.unread .time,.mail-card.unread .time{color:var(--accent-color)}.contact.unread h4,.contact.unread h5,.contact.unread p,.mail-card.unread h4,.mail-card.unread h5,.mail-card.unread p{font-weight:700}.mail-card{display:flex;flex-direction:column;padding:1rem 1.5rem}.mail-card .sender{color:rgba(var(--text-color),.9);font-weight:500;overflow:hidden;margin-right:1rem}.mail-card .date{margin-left:auto;font-weight:500;white-space:nowrap}.mail-card .subject{font-size:1em;margin-top:.5rem;font-weight:500}.mail-card .description{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:.9em;margin-top:.2rem;color:rgba(var(--text-color),.8)}#chat .message .message-body,.mail .mail-content,.mail .mail-subject{overflow-wrap:break-word;word-wrap:break-word}@keyframes slide{from{opacity:0;transform:translateX(-1rem)}to{opacity:1;transform:none}}#mail_container{width:100%}.mail:not(:first-of-type){margin-top:2rem;padding-inline-start:1rem}.mail:not(:first-of-type)::before{content:"";position:absolute;left:0;top:0;width:.2rem;height:100%;background:rgba(var(--text-color),.2)}.mail header{align-self:start;margin-bottom:1rem;padding-bottom:.5rem;border-bottom:solid 1px rgba(var(--text-color),.2)}.mail header h4{font-weight:500}.mail header .flo-id{font-weight:400;max-width:90%}.mail .mail-subject{margin-bottom:.4em}.mail .mail-content{height:max-content;max-width:60ch;white-space:pre-wrap}.logo-section{display:grid;grid-template-columns:auto 1fr}#main_navbar{position:fixed;flex-direction:column;bottom:0;top:0;padding:0;width:max(16rem,60vw);background:rgba(var(--foreground-color),1)}#main_navbar .logo-section{margin:1rem 0 1.5rem;padding:0 1rem}#main_navbar .active{background:var(--accent-color)}#main_navbar .active .icon{stroke:#fff}#main_navbar .active .label{color:#fff}#main_navbar .label{font-weight:500;font-size:.9rem}#main_navbar .navbar-item{height:auto;justify-content:flex-start;flex-direction:row;flex:none;padding:1rem}#main_navbar .navbar-item .icon{margin-right:.8rem;height:1.2rem;width:1.2rem}#main_navbar .navbar-item:last-of-type{margin-top:auto}#main_navbar .navbar-item.badge::after{right:0;top:0;position:absolute;content:attr(data-notifications);display:flex;justify-content:center;align-items:center;padding:.4rem;line-height:0;height:calc(1em + .4rem);background:#00C853;color:rgba(var(--foreground-color),1);border-radius:2rem;transition:transform .3s}#contacts #all_contacts,#mail_contact_list{position:absolute;background:rgba(var(--foreground-color),1);z-index:1}#main_navbar .navbar-item.badge.active::after,#main_navbar .navbar-item.badge[data-notifications=""]::after,#main_navbar .navbar-item.badge[data-notifications="0"]::after{transform:scale(0)}#auto_complete_contact{position:relative;justify-content:flex-start;padding-bottom:0}#mail_contact_list{max-height:40vh;overflow-y:auto;top:100%;border-radius:.4rem;box-shadow:0 .1rem .1rem rgba(0,0,0,.1),0 .2rem .5rem rgba(0,0,0,.16);width:100%}#mail_contact_list .contact{grid-template-columns:auto 1fr;grid-template-areas:"dp ." "dp ."}#mail_contact_list sm-menu{display:none}#contacts{position:relative}#contacts #all_contacts{top:0;bottom:0;left:0;right:0}#contacts #all_contacts .header{padding-top:.7rem}#contacts .option{display:flex;align-items:center;padding:1rem 1.5rem}#contacts .option .icon{margin-right:1rem;stroke:rgba(var(--text-color),.7)}#contacts .scrolling-wrapper{height:100%;flex:1;overflow-y:auto}#contacts #contacts_container{padding-bottom:5rem}#contacts #contacts_container::before{display:flex;content:"Contacts";font-size:.9em;color:rgba(var(--text-color),.9);padding:1rem 1.5rem}#selected_contacts{padding:1.5rem;background:rgba(var(--text-color),.06)}#selected_contacts h4{font-weight:500;font-size:1rem}#selected_contacts sm-button{margin-bottom:0}#selected_contacts_container{display:grid;grid-template-columns:repeat(auto-fill,minmax(6rem,1fr));gap:1rem}#contacts,#mails{position:relative;grid-template-rows:max-content 1fr}#contacts,#mails,#settings_page{height:100vh;overflow-y:hidden}#contacts .header,#mails .header,#settings_page .header{padding:1rem 1.5rem;position:relative;gap:.5rem;min-height:4rem}#contacts .header sm-tab::part(tab),#mails .header sm-tab::part(tab),#settings_page .header sm-tab::part(tab){padding:.8rem 1rem}#contacts .header .expanding-search,#mails .header .expanding-search,#settings_page .header .expanding-search{position:absolute;width:100%;padding:.7rem 1.5rem;background:rgba(var(--foreground-color),1);transform:scale(.9);opacity:0;pointer-events:none;transition:opacity .3s,transform .3s}#contacts .header .expanding-search.expand,#mails .header .expanding-search.expand,#settings_page .header .expanding-search.expand{transform:none;opacity:1;pointer-events:all}#contacts .header sm-input,#mails .header sm-input,#settings_page .header sm-input{margin:0;width:100%}#contacts .header sm-input .icon,#mails .header sm-input .icon,#settings_page .header sm-input .icon{stroke:rgba(var(--text-color),.5);height:.9rem;width:.9rem}#contacts .header sm-input::part(input),#mails .header sm-input::part(input),#settings_page .header sm-input::part(input){border-radius:3rem;padding:.2rem .8rem}#contacts .header h4,#mails .header h4,#settings_page .header h4{text-transform:capitalize;font-weight:500}#contacts .header .icon,#mails .header .icon,#settings_page .header .icon{-webkit-tap-highlight-color:transparent}#contacts .header .flex .hamburger-menu-button,#mails .header .flex .hamburger-menu-button,#settings_page .header .flex .hamburger-menu-button{-webkit-tap-highlight-color:transparent;margin-right:1rem}#contacts .header .flex h4,#mails .header .flex h4,#settings_page .header .flex h4{flex:1}#contacts .header .flex .icon,#mails .header .flex .icon,#settings_page .header .flex .icon{height:2.2rem;width:2.2rem;padding:.6rem;margin-left:-.4rem;cursor:pointer}#contacts .header .flex sm-menu,#mails .header .flex sm-menu,#settings_page .header .flex sm-menu{margin-right:-.7rem}#chat #type_message,#contacts .header sm-button,#mails .header sm-button,#settings_page .header sm-button{margin:0}#contacts .header sm-button .icon,#mails .header sm-button .icon,#settings_page .header sm-button .icon{height:.9rem;width:.9rem;align-self:center;stroke-width:8;margin-left:0;margin-right:.5rem}#chat_page{overflow-y:hidden}#chat{height:100%}#chat header{padding:1rem;min-height:4rem;grid-template-columns:auto 1fr auto}#chat header .back-button{padding:.1rem;stroke-width:8;margin-right:.5rem;stroke:rgba(var(--text-color),.8)}#chat header .initial{cursor:pointer;margin-right:1rem;height:2.2rem;width:2.2rem;flex-shrink:0}#chat header h4{font-weight:500;font-size:.9rem}#chat header #receiver_name{overflow:hidden}#chat #scroll_to_bottom{position:fixed;right:0;bottom:4rem;width:2.6rem;height:2.6rem;padding:.9rem;border-radius:4rem;z-index:1;margin:1.5rem;stroke-width:8;cursor:pointer;transform:scale(0);transition:transform .3s}#chat footer #emoji_toggle{align-self:center;padding:.6rem;width:2.6rem;height:2.6rem;border-radius:2rem;cursor:pointer}#chat footer #emoji_toggle path{fill:rgba(var(--text-color),.5)}#chat footer #emoji_toggle.active path{fill:var(--accent-color)}#chat footer .flex{align-items:flex-end;padding:1rem 1rem 1rem .4rem}#chat footer sm-textarea::part(textarea){background:rgba(var(--text-color),.1);padding-right:3rem;border-radius:2rem}#chat #send_message_button{position:absolute;right:1.5rem;transform:scale(0);opacity:0;pointer-events:none;z-index:1;align-self:center;height:2.4rem;width:2.4rem;padding:.5rem;cursor:pointer;stroke:none;fill:rgba(var(--text-color),.4);margin-left:1rem;transition:.3s}#chat #send_message_button.active{opacity:1;fill:var(--accent-color);transform:none;pointer-events:all}#chat .sent,#chat .sent .time{margin-left:auto}#chat .message{position:relative;display:grid;align-items:center;gap:.2rem;width:100%;font-size:.92rem;max-width:max-content;margin-bottom:.2rem;margin-top:.8rem;padding:.6em 1em}#chat .message .message-body{display:inline-flex;align-items:center;flex-wrap:wrap;word-break:break-all;word-break:break-word;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto;white-space:pre-wrap;line-height:1.6}#chat .message .message-body a{color:inherit}#chat .message .message-body .text-emoji{align-self:center;font-size:1.4em;letter-spacing:0ch}#chat .message .time{white-space:nowrap;font-size:.8em;opacity:.8}#chat .sent{background:var(--accent-color);color:#f0f0f0;border-radius:1em 0 1em 1em}#chat .sent::after{content:"";position:absolute;left:100%;top:0;width:0;height:0;border-style:solid;border-width:.5em .3em 0 0;border-color:var(--accent-color) transparent transparent}#chat .received{background:rgba(var(--text-color),.1);border-radius:0 1em 1em}#chat .received::after{content:"";position:absolute;left:-.5em;top:0;width:0;height:0;border-style:solid;border-width:0 .5em .5em 0;border-color:transparent rgba(var(--text-color),.1) transparent transparent}#chat .received+.received,#chat .sent+.sent{margin-top:0;border-radius:1em}#chat .received+.received::after,#chat .sent+.sent::after{display:none}#chat .unconfirmed{opacity:.7;transform-origin:right;animation:slide-up .3s forwards}@keyframes slide-up{from{transform:translateY(-2rem)}to{transform:none}}.big-emoji .message-body{font-size:2.6rem}#messages_container{flex:1;padding:0 1rem}#emoji_picker{display:grid;gap:1rem;background:rgba(var(--text-color),.06);border-radius:1rem;margin:0 1rem;box-shadow:0 .2rem .8rem rgba(0,0,0,.3);overflow-y:auto;max-height:30vh}#emoji_picker section{display:grid;grid-template-columns:repeat(auto-fill,minmax(3.6rem,1fr));gap:.5rem;padding:0 1rem;width:100%}#emoji_picker .section-header{grid-column:1/-1;position:sticky;top:0;background:linear-gradient(rgba(var(--text-color),.06),rgba(var(--text-color),.06)),rgba(var(--foreground-color),1);padding:1rem 0;z-index:1}.emoji{font-size:1.6rem;cursor:pointer;padding:.4rem;border-radius:.6rem;user-select:none;text-align:center}#new_conversation,#no_mails{height:100%;justify-content:center;text-align:center;padding:1.5rem}#new_conversation p,#no_mails p{margin-top:.8rem}#no_mails .new-conversation{height:7rem;margin-bottom:1rem}.new-conversation{height:8rem;width:8rem;align-self:center;stroke-width:16;stroke:rgba(var(--text-color),.4)}#chat_container,#inbox_mail_container,#mail,#messages_container,#sent_mail_container{width:100%;flex-direction:column;height:100%;overflow-y:auto}#chat_container:empty{display:none}#chat_container:not(:empty)~.empty-state{display:none}#chat_container{padding-bottom:6rem}sm-tab-panels{overflow:hidden auto}sm-panel{width:100%;overflow-y:auto}#inbox_mail_container,#sent_mail_container{padding-bottom:5rem}#chat,#mail{background:rgba(var(--foreground-color),1)}#mail{height:100vh;padding:0 1.5rem;align-items:flex-start}#mail .flex{margin-top:1rem}#mail .flex sm-button:first-of-type{margin-right:.5rem}#compose_mail_popup sm-input{margin-bottom:1rem}.sidebar-item{display:flex;align-items:center;padding:1rem 1.5rem;text-transform:capitalize;font-weight:500;opacity:.9}.sidebar-item .icon{margin-right:1em;width:1em}.back{padding:.7rem;height:2.4rem;width:2.4rem;margin-left:-.5rem;cursor:pointer;stroke-width:8;opacity:.8;-webkit-tap-highlight-color:transparent}.back:hover{opacity:1}#settings_page #settings_sidebar header{padding:1rem 1.5rem}#settings_page .flex sm-button{margin:0;margin-left:1rem}#settings_page sm-switch{padding-left:1rem}#settings_page sm-button{width:100%}#settings_page #settings_title{text-transform:capitalize}#settings_page #settings_sidebar{height:100%}#settings_page #settings_panel{padding:0 1.5rem}#settings_page section{max-width:50ch;display:grid;gap:.3rem}#settings_page section sm-button{margin-top:.5rem;margin-bottom:0}#settings_page section:not(:last-of-type){margin-bottom:2rem}#settings_page section.setting-toggle{grid-template-columns:1fr auto}#settings_page section.setting-toggle sm-switch{grid-column:2;grid-row:1/3}#settings_page section.setting-toggle>h4,#settings_page section.setting-toggle>p{grid-column:1}#settings_page #sign_out::part(button){color:var(--error-color)}@media screen and (max-width:640px){.hide-on-mobile{position:fixed;max-height:0;opacity:0;pointer-events:none}#landing{grid-template-areas:"illustration" ".";align-items:flex-start}#landing .title-font{text-align:center;font-size:2rem;font-weight:500}#landing .left p{text-align:center}#landing sm-button{display:flex;width:100%!important}#sing_in{max-height:90vh}#landing_illustration{grid-area:illustration}#main_navbar{transform:translateX(-100%);transition:transform .3s;z-index:4;box-shadow:0 0 1rem rgba(0,0,0,.3)}#main_navbar .logo-section{padding:1rem}#navbar_backdrop{position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0,0,0,.3);z-index:2;transition:transform .3s,opacity .3s}#chat_container,#contact_container{gap:.2rem}#chat .message{width:fit-content;max-width:90%}#settings_page{overflow-x:hidden}#settings_page #settings_panel header{position:sticky;top:0;padding:1rem 0;margin-bottom:.5rem;background:rgba(var(--foreground-color),1)}}@media only screen and (min-width:640px){::-webkit-scrollbar{width:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color),.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color),.5)}.hide-on-desktop{display:none!important}.page{padding-bottom:0}.fab{position:absolute}.logo-section{padding:2rem 3rem 0;margin:.5rem 0}sm-popup::part(popup){width:24rem;min-width:24rem}#landing{align-items:center;gap:4vw;grid-template-columns:1fr 1fr;padding:0 4vw}#landing .left h4{color:var(--accent-color)}#sign_in_popup .popup-header{padding-top:1.5rem}#main_navbar{position:relative;width:auto;padding-bottom:.5rem;background:rgba(var(--text-color),.06)}#main_navbar .logo-section{display:flex;justify-content:center;margin:1.5rem 0}#main_navbar .logo-section .main-logo{margin:0}#main_navbar .navbar-item{margin:0 .5rem;border-radius:.8rem}#main_navbar .navbar-item .icon{margin-right:0}#main_navbar .label{display:none}#add_contact_popup::part(popup){min-width:24rem}#compose_mail_popup::part(popup),#reply_mail_popup::part(popup){min-width:36rem}#main{width:100vw;height:100vh;grid-template-columns:auto 1fr}#emoji_picker{max-height:18rem}#chat .message .message-body{max-width:65ch}#chat_page,#mail_page{grid-template-columns:20rem 1fr;box-shadow:0 0 1rem rgba(0,0,0,.1);z-index:1}#settings_page{display:grid;height:100vh;box-shadow:0 0 1rem rgba(0,0,0,.1);grid-template-columns:14rem 1fr}#settings_page sm-button{width:max-content}#settings_page #settings_panel{padding:1.5rem}#settings_page .active{background:rgba(var(--text-color),.1)}.contact.active,.mail-card.active{background:rgba(var(--text-color),.06)}.card{display:inline-flex;width:auto}#settings_panel{overflow-y:auto;max-height:100vh}}@media only screen and (min-width:1280px){#landing{gap:4vw;padding:0 8vw}#landing .title-font{font-size:3rem}#chat_page,#mail_page{grid-template-columns:21rem 1fr}#chat header{padding:.8rem 1.5rem}#chat #messages_container{padding:1rem 5rem}}@media (hover:hover){.contact:hover,.mail-card:hover,.navbar-item:hover{background:rgba(var(--text-color),.06);cursor:pointer}.contact .menu{opacity:0;transition:opacity .3s}.contact:hover .menu{opacity:1}.emoji:hover{background:rgba(var(--text-color),.1)}}@media (hover:none){.contact .menu{display:none}} \ No newline at end of file +body,body #scroll_to_bottom{background:rgba(var(--foreground-color),1)}p,textarea{line-height:1.6}.card,.flex,.popup-header{display:flex}.align-center,.popup-header{align-items:center}.contact .last-message,.contact .name,.copy-row .copy,.mail-card .sender,.text-overflow{white-space:nowrap;text-overflow:ellipsis}*,::after,::before{padding:0;margin:0;box-sizing:border-box;font-family:Roboto,sans-serif}:root{scroll-behavior:smooth;font-size:clamp(1rem,1.2vmax,3rem)}body,html{height:100%}body{--accent-color:#5b00d3;--secondary-color:#ffac2e;--text-color:17,17,17;--text-color-light:100,100,100;--foreground-color:255,255,255;--background-color:#efefef;--error-color:red;color:rgba(var(--text-color),1)}body #scroll_to_bottom{box-shadow:0 .3rem .4rem rgba(0,0,0,.2)}body[data-theme=dark]{--accent-color:#923eff;--secondary-color:#d60739;--text-color:240,240,240;--text-color-light:170,170,170;--foreground-color:20,20,20}body[data-theme=dark] .initial{color:rgba(var(--text-color),1)!important;box-shadow:0 .1rem .1rem rgba(0,0,0,.16)}body[data-theme=dark] .message,h1,h2,h3,h4,h5,textarea{color:rgba(var(--text-color),1)}body[data-theme=dark] #scroll_to_bottom{background:linear-gradient(rgba(var(--text-color),.1),rgba(var(--text-color),.1)),rgba(var(--foreground-color),1);box-shadow:0 .4rem .4rem rgba(0,0,0,.3)}h1{font-size:3rem}h2{font-size:2rem}h3{font-size:1.5rem}h4{font-size:1.1rem}h5{font-size:.8rem}h1,h2,h3,h4,h5{font-weight:600}textarea{background:rgba(var(--text-color),.06);border:none;border-radius:.3rem;width:100%;padding:1rem;font-size:1rem;resize:none}textarea:focus{outline:0;box-shadow:0 0 0 .1rem var(--accent-color)}strong{font-weight:500}.grid{display:grid}.grid-2{grid-template-columns:auto auto;gap:1em}.justify-right{margin-left:auto}.direction-column{flex-direction:column}.rest{flex:1}.hide{opacity:0;pointer-events:none}.hide-completely{display:none!important}.no-transformations{transform:none!important}.breakable{overflow-wrap:break-word}.text-overflow{overflow:hidden}.sticky{position:sticky;top:1rem}.light-text{color:rgba(var(--text-color-light),1)}.accent-color{color:var(--accent-color)}.secondary-color{color:var(--secondary-color)}.fab{filter:drop-shadow(0 .4rem .3rem rgba(0, 0, 0, .2));margin:1.5rem;position:fixed;right:0;bottom:0;z-index:1}.fab::part(button){padding:.9rem 1.6rem}.fab .icon{margin-left:0!important;margin-right:.5rem;height:.9rem!important;stroke-width:8!important}a:any-link{word-wrap:break-word;color:var(--accent-color);font-weight:500}.solid-background{background:var(--background-color)!important}.normal-weight{font-weight:400}.icon{fill:none;stroke-width:6;stroke:rgba(var(--text-color),1);height:1.2rem;width:1.2rem;overflow:visible;stroke-linecap:round;stroke-linejoin:round}span.ripple{position:absolute;border-radius:50%;transform:scale(0);background:rgba(var(--text-color),.2);pointer-events:none}#landing_illustration,.contact,.initial,.interact,.logo-section{position:relative}#landing_page,.sign-in-box{background:rgba(var(--foreground-color),1)}.interact{overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}sm-popup sm-input+sm-input{margin-top:1rem}.popup-header{padding:.5rem 1.5rem 0;width:100%}.popup-header .icon{padding:.7rem;height:2.4rem;width:2.4rem;stroke-width:8;transform:translateX(-.5rem);cursor:pointer;-webkit-tap-highlight-color:transparent}.popup-header .back{transform:none}.popup-header button,.popup-header sm-button{width:auto;margin-left:auto}.copy-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.5rem;width:auto}.copy-row .icon{cursor:pointer;padding:.4rem;height:1.8rem;width:1.8rem}.copy-row .copy{overflow:hidden}.copy-row h4{margin-bottom:0!important}#confirmation_popup,#prompt_popup{flex-direction:column}#confirmation_popup h4,#prompt_popup h4{font-weight:500;margin-bottom:.5rem}#confirmation_popup sm-button,#prompt_popup sm-button{margin:0}#confirmation_popup .flex,#prompt_popup .flex{padding:0;margin-top:2rem}#confirmation_popup .flex sm-button:first-of-type,#prompt_popup .flex sm-button:first-of-type{margin-right:.6rem;margin-left:auto}.card,sm-button{margin:1rem 0}.page{align-items:flex-start;width:100%;height:100%}.card{flex-direction:column}sm-button .icon{margin-right:.4rem}sm-button[variant=primary]{--foreground-color:255,255,255}sm-button[variant=primary] .icon{align-self:center;height:1rem;width:1rem;margin-left:.8rem;stroke-width:6;stroke:#fff}.logo-section{align-items:center;height:max-content;margin:.5rem 0}.logo-section h5{font-size:1.1rem!important;font-weight:500}.logo-section .main-logo{height:1.4rem;margin-right:.4rem;fill:rgba(var(--text-color),1);stroke:none}.logo-section img{width:2rem;margin-right:.5rem}.select-file input[type=file]{display:none}#landing{display:grid;border-radius:.6rem;width:100%;padding:0 1.5rem;height:100%;align-items:center;overflow-y:auto}#landing .logo-section{padding:1.5rem;display:flex}#landing .title-font{line-height:1.2;font-weight:700;font-size:2.5rem}#landing .left{display:grid;flex-direction:column;padding-bottom:1.5rem;z-index:1}#landing .left h4{color:rgba(var(--foreground-color),1);font-weight:500}#landing .left p,.contact .last-message,.contact .name{color:rgba(var(--text-color),.8)}#landing .left sm-button{margin:1.5rem 0 2rem;width:max-content}#landing_illustration,.sign-in-box,.sign-in-box form,.sign-in-box sm-button,.sign-in-box sm-panel{width:100%}#landing .left h3{margin-bottom:1rem;font-weight:500}#landing .left p{margin-top:1rem;font-size:1.1rem}.logo-section{padding:1.5rem}#sign_in_popup::part(popup-body){padding:0}.sign-in-box{margin:0 -2rem;z-index:1;justify-self:center;padding:1.5rem;border-radius:.5rem}.sign-in-box sm-input{margin-top:1.5rem}.sign-in-box sm-tab-header{margin:0;background:0 0;align-self:flex-start}.sign-in-box sm-tab-header::part(tab-header){padding-bottom:.4rem;gap:1.5rem}.sign-in-box sm-tab::part(tab){padding:.4rem 0}.sign-in-box sm-tab-panels{margin-top:1.5rem}.sign-in-box h2{margin-bottom:.5rem}.sign-in-box h3{font-weight:500}.sign-in-box h4{font-weight:500;margin-bottom:1.5rem}.sign-in-box h5{opacity:.8;font-weight:500}.sign-in-box strong{display:flex;background:#ffd92e;padding:.4em .6em;border-radius:.4em;color:#111;margin-top:.5rem}.sign-in-box .copy-row h4{max-width:34ch}.sign-in-box .copy-row:not(:last-of-type){margin-bottom:1rem}.sign-in-box button{margin-top:2rem;padding:.6rem 1.6rem}.sign-in-box sm-button::part(button){padding:.8rem 1.6rem}.sign-in-box p{margin-bottom:.5rem;max-width:35ch;margin-top:.5rem}.sign-in-box #credentials_section{border-top:1px rgba(var(--text-color),.2) solid;margin-top:1rem;padding-top:1.5rem;animation:slide-down .3s forwards}.sign-in-box #sign_in_with,.sign-in-box sm-button{margin-top:2rem;margin-bottom:0}@keyframes slide-down{from{transform:translateY(-1rem)}to{transform:none}}#loading_page{height:100vh;display:grid;place-content:center;justify-items:center}#loading_page svg{z-index:1;transform-origin:bottom;height:6rem;width:6rem;animation:bounce .5s infinite alternate ease-in}#loading_page .shadow{margin-top:-1rem;width:5rem;height:2rem;background:rgba(var(--text-color),.1);border-radius:50%;animation:scale .5s infinite alternate ease-in;margin-left:1rem}#loading_page h4{margin-top:2rem}@keyframes bounce{0%{transform:scaleY(1) translateY(-4rem)}90%{transform:scaleY(1) translateY(0)}100%{transform:scaleY(.8)}}@keyframes scale{0%{transform:scale(.5)}90%{transform:scale(1.05)}100%{transform:scale(1)}}.initial{justify-content:center;font-size:1.2rem;width:2.5rem;height:2.5rem;color:#fff;box-shadow:0 .1rem .1rem rgba(0,0,0,.06);border-radius:2rem;text-transform:uppercase;user-select:none}.group-icon{height:1.6rem;width:1.6rem;fill:#fff;stroke:none}.contact{display:grid;gap:0 1rem;padding:.8rem 1.5rem;align-items:center;flex-shrink:0;overflow:hidden}.contact:not(.chat){grid-template-columns:auto 1fr;grid-template-areas:"dp ."}.contact.chat,.contact.group{grid-template-columns:auto 1fr auto;grid-template-areas:"dp . time" "dp . menu"}.contact .initial{grid-area:dp}.contact .name{font-size:1em;font-weight:500;overflow:hidden}.contact .last-message{overflow:hidden;font-weight:400;font-size:.9em}.contact .menu{grid-area:menu;justify-self:flex-end;padding:.2rem;fill:rgba(var(--text-color),1)}.contact .time{font-weight:500;color:rgba(var(--text-color),.7);grid-area:time}#contact_details_popup>.flex:first-of-type{margin:1rem 0}#contact_details_popup>.flex:first-of-type .flex .icon{height:2.6rem;width:2.6rem;padding:.85rem;cursor:pointer;stroke-width:8}#contact_details_popup>.flex:first-of-type .flex .icon:hover{background:rgba(var(--text-color),.06)}#contact_details_popup h5{font-weight:500;opacity:.8}#contact_details_popup .copy-row{margin-bottom:1.5rem}#contact_details_popup .copy-row h4{font-weight:400}#contact_details_popup .group-icon{padding:.2rem!important}#contact_details_popup #contact_initial{height:3.6rem;width:3.6rem;font-size:1.6rem;border-radius:4rem;margin-bottom:1rem}#contact_details_popup #contact_name{border-radius:.5rem;max-width:30ch;padding:.6rem 1.2rem;overflow-wrap:break-word}#contact_details_popup #contact_name:focus{outline:0;background:rgba(var(--text-color),.1)}#warn_no_encryption,.date-card,.group-event-card{padding:.4rem .8rem;background:rgba(var(--text-color),.1);font-weight:500;border-radius:.5rem;color:rgba(var(--text-color),.8);margin:1rem 0;justify-self:center;align-self:center;text-align:center}.group-event-card{font-size:.8rem;font-weight:400}#warn_no_encryption{background:#fffd8d;color:#111}.mail-card.unread::before{content:"";position:absolute;padding:.4rem;border-radius:1rem;top:0;left:0;background:var(--accent-color)}.contact .initial::after{content:"";position:absolute;height:calc(100% + .8rem);width:calc(100% + .8rem);border:var(--accent-color) solid;border-radius:100%;transform:scale(.8);opacity:0;transition:transform .3s,opacity .3s}.mail,.mail-card{position:relative}.contact.unread .initial::after{transform:scale(1);opacity:1}.contact.unread .time,.mail-card.unread .time{color:var(--accent-color)}.contact.unread h4,.contact.unread h5,.contact.unread p,.mail-card.unread h4,.mail-card.unread h5,.mail-card.unread p{font-weight:700}.mail-card{display:flex;flex-direction:column;padding:1rem 1.5rem}.mail-card .sender{color:rgba(var(--text-color),.9);font-weight:500;overflow:hidden;margin-right:1rem}.mail-card .date{margin-left:auto;font-weight:500;white-space:nowrap}.mail-card .subject{font-size:1em;margin-top:.5rem;font-weight:500}.mail-card .description{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:.9em;margin-top:.2rem;color:rgba(var(--text-color),.8)}#chat .message .message-body,.mail .mail-content,.mail .mail-subject{overflow-wrap:break-word;word-wrap:break-word}@keyframes slide{from{opacity:0;transform:translateX(-1rem)}to{opacity:1;transform:none}}#mail_container{width:100%}.mail:not(:first-of-type){margin-top:2rem;padding-inline-start:1rem}.mail:not(:first-of-type)::before{content:"";position:absolute;left:0;top:0;width:.2rem;height:100%;background:rgba(var(--text-color),.2)}.mail header{align-self:start;margin-bottom:1rem;padding-bottom:.5rem;border-bottom:solid 1px rgba(var(--text-color),.2)}.mail header h4{font-weight:500}.mail header .flo-id{font-weight:400;max-width:90%}.mail .mail-subject{margin-bottom:.4em}.mail .mail-content{height:max-content;max-width:60ch;white-space:pre-wrap}.logo-section{display:grid;grid-template-columns:auto 1fr}#main_navbar{position:fixed;flex-direction:column;bottom:0;top:0;padding:0;width:max(16rem,60vw);background:rgba(var(--foreground-color),1)}#main_navbar .logo-section{margin:1rem 0 1.5rem;padding:0 1rem}#main_navbar .active{background:var(--accent-color)}#main_navbar .active .icon{stroke:#fff}#main_navbar .active .label{color:#fff}#main_navbar .label{font-weight:500;font-size:.9rem}#main_navbar .navbar-item{height:auto;justify-content:flex-start;flex-direction:row;flex:none;padding:1rem}#main_navbar .navbar-item .icon{margin-right:.8rem;height:1.2rem;width:1.2rem}#main_navbar .navbar-item:last-of-type{margin-top:auto}#main_navbar .navbar-item.badge::after{right:0;top:0;position:absolute;content:attr(data-notifications);display:flex;justify-content:center;align-items:center;padding:.4rem;line-height:0;height:calc(1em + .4rem);background:#00C853;color:rgba(var(--foreground-color),1);border-radius:2rem;transition:transform .3s}#contacts #all_contacts,#mail_contact_list{position:absolute;background:rgba(var(--foreground-color),1);z-index:1}#emoji_picker,#selected_contacts{background:rgba(var(--text-color),.06)}#main_navbar .navbar-item.badge.active::after,#main_navbar .navbar-item.badge[data-notifications=""]::after,#main_navbar .navbar-item.badge[data-notifications="0"]::after{transform:scale(0)}#auto_complete_contact{position:relative;justify-content:flex-start;padding-bottom:0}#mail_contact_list{max-height:40vh;overflow-y:auto;top:100%;border-radius:.4rem;box-shadow:0 .1rem .1rem rgba(0,0,0,.1),0 .2rem .5rem rgba(0,0,0,.16);width:100%}#mail_contact_list .contact{grid-template-columns:auto 1fr;grid-template-areas:"dp ." "dp ."}#mail_contact_list sm-menu{display:none}#contacts{position:relative}#contacts #all_contacts{top:0;bottom:0;left:0;right:0}#contacts #all_contacts .header{padding-top:.7rem}#contacts .option{display:flex;align-items:center;padding:1rem 1.5rem}#contacts .option .icon{margin-right:1rem;stroke:rgba(var(--text-color),.7)}#contacts .scrolling-wrapper{height:100%;flex:1;overflow-y:auto}#contacts #contacts_container{padding-bottom:5rem}#contacts #contacts_container::before{display:flex;content:"Contacts";font-size:.9em;color:rgba(var(--text-color),.9);padding:1rem 1.5rem}#selected_contacts{padding:1.5rem}#selected_contacts h4{font-weight:500;font-size:1rem}#selected_contacts sm-button{margin-bottom:0}#selected_contacts_container{display:grid;grid-template-columns:repeat(auto-fill,minmax(3rem,1fr));gap:1rem;max-height:8rem;overflow-y:auto}#contacts,#mails{position:relative;grid-template-rows:max-content 1fr}#contacts,#mails,#settings_page{height:100vh;overflow-y:hidden}#contacts .header,#mails .header,#settings_page .header{padding:1rem 1.5rem;position:relative;gap:.5rem;min-height:4rem}#contacts .header sm-tab::part(tab),#mails .header sm-tab::part(tab),#settings_page .header sm-tab::part(tab){padding:.8rem 1rem}#contacts .header .expanding-search,#mails .header .expanding-search,#settings_page .header .expanding-search{position:absolute;width:100%;padding:.7rem 1.5rem;background:rgba(var(--foreground-color),1);transform:scale(.9);opacity:0;pointer-events:none;transition:opacity .3s,transform .3s}#contacts .header .expanding-search.expand,#mails .header .expanding-search.expand,#settings_page .header .expanding-search.expand{transform:none;opacity:1;pointer-events:all}#contacts .header sm-input,#mails .header sm-input,#settings_page .header sm-input{margin:0;width:100%}#contacts .header sm-input .icon,#mails .header sm-input .icon,#settings_page .header sm-input .icon{stroke:rgba(var(--text-color),.5);height:.9rem;width:.9rem}#contacts .header sm-input::part(input),#mails .header sm-input::part(input),#settings_page .header sm-input::part(input){border-radius:.5rem;padding:.2rem .8rem}#contacts .header h4,#mails .header h4,#settings_page .header h4{text-transform:capitalize;font-weight:500}#contacts .header .icon,#mails .header .icon,#settings_page .header .icon{-webkit-tap-highlight-color:transparent}#contacts .header .flex .hamburger-menu-button,#mails .header .flex .hamburger-menu-button,#settings_page .header .flex .hamburger-menu-button{-webkit-tap-highlight-color:transparent;margin-right:1rem}#contacts .header .flex h4,#mails .header .flex h4,#settings_page .header .flex h4{flex:1}#chat .message,#chat_details_panel,#chat_left{position:relative;flex-direction:column;display:flex}#contacts .header .flex .icon,#mails .header .flex .icon,#settings_page .header .flex .icon{height:2.2rem;width:2.2rem;padding:.6rem;margin-left:-.4rem;cursor:pointer}#contacts .header .flex sm-menu,#mails .header .flex sm-menu,#settings_page .header .flex sm-menu{margin-right:-.7rem}#contacts .header sm-button,#mails .header sm-button,#settings_page .header sm-button,#type_message{margin:0}#contacts .header sm-button .icon,#mails .header sm-button .icon,#settings_page .header sm-button .icon{height:.9rem;width:.9rem;align-self:center;stroke-width:8;margin-left:0;margin-right:.5rem}#chat_page{overflow-y:hidden}#chat_details_panel,#chat_left{height:100%;overflow-y:auto}#chat_details_panel{background:rgba(var(--text-color),.04);padding-bottom:1.5rem}#chat_details_panel .card{margin:0 1rem;padding:1.5rem 1rem;border-radius:.8rem;background:rgba(var(--text-color),.04)}#chat_details_panel .card:not(:last-of-type){margin-bottom:1rem}#chat_details_panel .card>h4{font-weight:400;font-size:.9rem;color:rgba(var(--text-color),.8);margin-bottom:.5rem}#chat_details_panel header{padding:1rem;min-height:4rem}#chat_details_panel header .icon{height:2.3rem;width:2.3rem;padding:.7rem;cursor:pointer}#chat_details_panel .contact{padding:.5rem 0}#chat_details_panel #chat_profile{display:grid;place-items:center;margin-top:1.5rem;padding-bottom:1.5rem}#chat_details_panel #chat_profile .initial{margin-top:-5.5rem;margin-bottom:1rem;height:8rem;width:8rem;border-radius:50%;font-size:4rem}#chat_details_panel #chat_profile .initial .icon{height:4rem;width:4rem}#chat_details_panel #chat_profile #chat_name{font-weight:500;font-size:1.2rem}#chat_details_panel #chat_profile #last_interaction_time{color:rgba(var(--text-color),.7);font-size:.9rem;margin-top:.5rem}#chat_details_panel .copy{font-weight:400}#chat{position:relative;grid-template-columns:1fr}#chat .message{width:auto;font-size:.92rem;max-width:max-content;margin-bottom:.2rem;margin-top:.8rem;padding:.6em 1em;transition:opacity .3s,transform .3s cubic-bezier(.175,.885,.32,1.275)}#chat .message .sender-name{font-size:.85rem;font-weight:500;margin-bottom:.3rem}#chat .message .message-body{display:flex;align-items:center;flex-wrap:wrap;word-break:break-all;word-break:break-word;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto;white-space:pre-wrap;line-height:1.5}#chat .message .message-body a{color:inherit}#chat .message .message-body .text-emoji{align-self:center;font-size:1.4em;letter-spacing:0ch}#chat .message .time{white-space:nowrap;font-size:.8em;opacity:.8;justify-self:flex-end;padding-left:1rem;align-self:flex-end;margin-top:.2rem}#chat .sent{margin-left:auto;color:#efefef;background:var(--accent-color);border-radius:.8rem 0 .8rem .8rem}#chat .sent::after{content:"";position:absolute;left:100%;top:0;width:0;height:0;border-style:solid;border-width:.5em .3em 0 0;border-color:var(--accent-color) transparent transparent}#chat .received{background:rgba(var(--text-color),.1);border-radius:0 .8rem .8rem}#chat .received::after{content:"";position:absolute;left:-.5em;top:0;width:0;height:0;border-style:solid;border-width:0 .5em .5em 0;border-color:transparent rgba(var(--text-color),.1) transparent transparent}#chat .received+.received,#chat .sent+.sent{margin-top:0;border-radius:.8rem}#chat .received+.received::after,#chat .sent+.sent::after{display:none}#chat .unconfirmed{opacity:.7;transform-origin:left;animation:pop .3s forwards cubic-bezier(.175,.885,.32,1.275)}@keyframes pop{0%{transform:rotate(5deg) translate(-.5rem,1rem)}100%{transform:rotate(0) translate(0,0)}}#chat_header{padding:1rem;min-height:4rem;grid-template-columns:auto 1fr auto}#chat_header .back-button{height:2rem;width:2rem;padding:.5rem;stroke-width:8;margin-right:.5rem;stroke:rgba(var(--text-color),.8)}#chat_header .initial{cursor:pointer;margin-right:1rem;height:2.2rem;width:2.2rem;flex-shrink:0}#chat_header #receiver_name{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#scroll_to_bottom{position:absolute;display:flex;right:0;bottom:4rem;border-radius:4rem;z-index:1;aspect-ratio:1/1;margin:1.5rem;cursor:pointer;transform:scale(0);transition:transform .3s}#scroll_to_bottom.new-message::after{position:absolute;content:"";top:0;right:0;z-index:2;padding:.5rem;border-radius:50%;background:#00E676}#scroll_to_bottom .icon{width:2.6rem;height:2.6rem;padding:.9rem;stroke-width:8}#chat_footer #emoji_toggle{align-self:center;padding:.6rem;margin-right:.5rem;width:2.6rem;height:2.6rem;border-radius:2rem;cursor:pointer}#chat_footer #emoji_toggle path{fill:rgba(var(--text-color),.5)}#chat_footer #emoji_toggle.active path{fill:var(--accent-color)}#chat_footer .flex{align-items:flex-end;padding:1rem 1rem 1rem .4rem}#chat_footer sm-textarea::part(textarea){padding-right:3rem;border-radius:.5rem}#send_message_button{position:absolute;right:1.5rem;transform:scale(0);opacity:0;pointer-events:none;z-index:1;align-self:center;height:2.4rem;width:2.4rem;padding:.5rem;cursor:pointer;stroke:none;fill:rgba(var(--text-color),.4);margin-left:1rem;transition:.3s}#send_message_button.active{opacity:1;fill:var(--accent-color);transform:none;pointer-events:all}.big-emoji .message-body{font-size:2.6rem}#chat_middle{flex:1;padding:0 1rem}#messages_container{height:100%}#emoji_picker{display:grid;gap:1rem;border-radius:1rem;margin:0 1rem;box-shadow:0 .2rem .8rem rgba(0,0,0,.3);overflow-y:auto;max-height:30vh}#emoji_picker section{display:grid;grid-template-columns:repeat(auto-fill,minmax(3.6rem,1fr));gap:.5rem;padding:0 1rem;width:100%}#emoji_picker .section-header{grid-column:1/-1;position:sticky;top:0;background:linear-gradient(rgba(var(--text-color),.06),rgba(var(--text-color),.06)),rgba(var(--foreground-color),1);padding:1rem 0;z-index:1;user-select:none}.emoji{font-size:1.6rem;cursor:pointer;padding:.4rem;border-radius:.6rem;user-select:none;text-align:center}#new_conversation,#no_mails{height:100%;justify-content:center;text-align:center;padding:1.5rem}#new_conversation p,#no_mails p{margin-top:.8rem}#no_mails .new-conversation{height:7rem;margin-bottom:1rem}.new-conversation{height:8rem;width:8rem;align-self:center;stroke-width:16;stroke:rgba(var(--text-color),.4)}#chat_container,#chat_middle,#inbox_mail_container,#mail,#sent_mail_container{width:100%;flex-direction:column;height:100%;overflow-y:auto}#chat_container:empty{display:none}#chat_container:not(:empty)~.empty-state{display:none}#chat_container{padding-bottom:6rem}sm-tab-panels{overflow:hidden auto}sm-panel{width:100%;overflow-y:auto}#inbox_mail_container,#sent_mail_container{padding-bottom:5rem}#chat,#mail{background:rgba(var(--foreground-color),1)}#mail{height:100vh;padding:0 1.5rem;align-items:flex-start}#mail .flex{margin-top:1rem}#mail .flex sm-button:first-of-type{margin-right:.5rem}#compose_mail_popup sm-input{margin-bottom:1rem}.sidebar-item{display:flex;align-items:center;padding:1rem 1.5rem;text-transform:capitalize;font-weight:500;opacity:.9}.sidebar-item .icon{margin-right:1em;width:1em}.back{padding:.7rem;height:2.4rem;width:2.4rem;margin-left:-.5rem;cursor:pointer;stroke-width:8;opacity:.8;-webkit-tap-highlight-color:transparent}.back:hover{opacity:1}#settings_page #settings_sidebar header{padding:1rem 1.5rem}#settings_page .flex sm-button{margin:0;margin-left:1rem}#settings_page sm-switch{padding-left:1rem}#settings_page sm-button{width:100%}#settings_page #settings_title{text-transform:capitalize}#settings_page #settings_sidebar{height:100%}#settings_page #settings_panel{padding:0 1.5rem}#settings_page section{max-width:50ch;display:grid;gap:.3rem}#settings_page section sm-button{margin-top:.5rem;margin-bottom:0}#settings_page section:not(:last-of-type){margin-bottom:2rem}#settings_page section.setting-toggle{grid-template-columns:1fr auto}#settings_page section.setting-toggle sm-switch{grid-column:2;grid-row:1/3}#settings_page section.setting-toggle>h4,#settings_page section.setting-toggle>p{grid-column:1}#settings_page #sign_out::part(button){color:var(--error-color)}@media screen and (max-width:640px){.hide-on-mobile{position:fixed;max-height:0;opacity:0;pointer-events:none}#landing{grid-template-areas:"illustration" ".";align-items:flex-start}#landing .title-font{text-align:center;font-size:2rem;font-weight:500}#landing .left p{text-align:center}#landing sm-button{display:flex;width:100%!important}#sing_in{max-height:90vh}#landing_illustration{grid-area:illustration}#main_navbar{transform:translateX(-110%);transition:transform .3s;z-index:4;box-shadow:0 0 1rem rgba(0,0,0,.3)}#main_navbar .logo-section{padding:1rem}#navbar_backdrop{position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0,0,0,.3);z-index:2;transition:transform .3s,opacity .3s}#chat_container,#contact_container{gap:.2rem}#chat .message{width:fit-content;max-width:90%}#settings_page{overflow-x:hidden}#settings_page #settings_panel header{position:sticky;top:0;padding:1rem 0;margin-bottom:.5rem;background:rgba(var(--foreground-color),1)}}@media only screen and (min-width:640px){.hide-on-desktop{display:none!important}.page{padding-bottom:0}.fab{position:absolute}.logo-section{padding:2rem 3rem 0;margin:.5rem 0}sm-popup::part(popup){width:24rem;min-width:24rem}#landing{align-items:center;gap:4vw;grid-template-columns:1fr 1fr;padding:0 4vw}#landing .left h4{color:var(--accent-color)}#sign_in_popup .popup-header{padding-top:1.5rem}#main_navbar{position:relative;width:auto;padding-bottom:.5rem;background:rgba(var(--text-color),.06);margin:.5rem;border-radius:.8rem}#main_navbar .logo-section{display:flex;justify-content:center;margin:1rem 0 2rem}#main_navbar .logo-section .main-logo{margin:0}#main_navbar .navbar-item{margin:0 .5rem;border-radius:.8rem}#main_navbar .navbar-item .icon{margin-right:0}#main_navbar .label{display:none}#add_contact_popup::part(popup){min-width:24rem}#compose_mail_popup::part(popup),#reply_mail_popup::part(popup){min-width:36rem}#main{width:100vw;height:100vh;grid-template-columns:auto 1fr}#emoji_picker{max-height:18rem}#chat .message{width:auto;align-self:flex-start;max-width:55ch}#chat_page,#mail_page{grid-template-columns:20rem 1fr}#settings_page{display:grid;height:100vh;grid-template-columns:14rem 1fr}#settings_page sm-button{width:max-content}#settings_page #settings_panel{padding:1.5rem}#settings_page .active{background:rgba(var(--text-color),.1)}.contact.active,.mail-card.active{background:rgba(var(--text-color),.06)}.card{display:inline-flex;width:auto}#settings_panel{overflow-y:auto;max-height:100vh}}@media only screen and (max-width:1280px){.hide-on-medium{display:none!important}}@media only screen and (min-width:1080px){#chat #messages_container{padding:1rem 5rem}}@media only screen and (min-width:1280px){#landing{gap:4vw;padding:0 8vw}#landing .title-font{font-size:3rem}#chat_page,#mail_page{grid-template-columns:21rem 1fr}#chat_details_panel{position:relative}#chat.expand-side-panel{grid-template-columns:1fr 24rem}#chat.expand-side-panel #messages_container{padding:1rem}#chat .active{background:rgba(var(--text-color),.1)}.contact.active,.mail-card.active{background:rgba(var(--text-color),.06)}.card{display:inline-flex;width:auto}#settings_panel{overflow-y:auto;max-height:100vh}}@media (hover:hover){::-webkit-scrollbar{width:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color),.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color),.5)}.contact{cursor:pointer}.contact .menu{opacity:0;transition:opacity .3s}.contact:hover{background:rgba(var(--text-color),.06)}.contact:hover .menu{opacity:1}}@media (hover:none){.contact .menu{display:none}} \ No newline at end of file diff --git a/css/main.scss b/css/main.scss index 3c4d90f..93b612c 100644 --- a/css/main.scss +++ b/css/main.scss @@ -520,6 +520,7 @@ sm-button[variant="primary"]{ box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.06); border-radius: 2rem; text-transform: uppercase; + user-select: none; } .group-icon{ height: 1.6rem; @@ -602,6 +603,9 @@ sm-button[variant="primary"]{ font-weight: 400; } } + .group-icon{ + padding: 0.2rem !important; + } #contact_initial{ height: 3.6rem; width: 3.6rem; @@ -620,7 +624,7 @@ sm-button[variant="primary"]{ } } } -#warn_no_encryption, .date-card{ +#warn_no_encryption, .date-card, .group-event-card{ padding: 0.4rem 0.8rem; background: rgba(var(--text-color), 0.1); font-weight: 500; @@ -629,6 +633,11 @@ sm-button[variant="primary"]{ margin: 1rem 0; justify-self: center; align-self: center; + text-align: center; +} +.group-event-card{ + font-size: 0.8rem; + font-weight: 400; } #warn_no_encryption{ background: rgb(255, 253, 141); @@ -900,8 +909,10 @@ sm-button[variant="primary"]{ } #selected_contacts_container{ display: grid; - grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(3rem, 1fr)); gap: 1rem; + max-height: 8rem; + overflow-y: auto; } #contacts, #mails{ position: relative; @@ -945,7 +956,7 @@ sm-button[variant="primary"]{ } } sm-input::part(input){ - border-radius: 3rem; + border-radius: 0.5rem; padding: 0.2rem 0.8rem; } h4{ @@ -990,114 +1001,97 @@ sm-button[variant="primary"]{ #chat_page{ overflow-y: hidden; } -#chat{ +#chat_left, +#chat_details_panel{ + position: relative; + display: flex; + flex-direction: column; height: 100%; + overflow-y: auto; +} +#chat_details_panel{ + background: rgba(var(--text-color), 0.04); + padding-bottom: 1.5rem; + .card{ + margin: 0 1rem; + padding: 1.5rem 1rem; + border-radius: 0.8rem; + background: rgba(var(--text-color), 0.04); + &:not(:last-of-type){ + margin-bottom: 1rem; + } + & > h4{ + font-weight: 400; + font-size: 0.9rem; + color: rgba(var(--text-color), 0.8); + margin-bottom: 0.5rem; + } + } header{ padding: 1rem; min-height: 4rem; - grid-template-columns: auto 1fr auto; - .back-button{ - padding: 0.1rem; - stroke-width: 8; - margin-right: 0.5rem; - stroke: rgba(var(--text-color), 0.8); + .icon{ + height: 2.3rem; + width: 2.3rem; + padding: 0.7rem; + cursor: pointer; } + } + .contact{ + padding: 0.5rem 0; + } + #chat_profile{ + display: grid; + place-items: center; + margin-top: 1.5rem; + padding-bottom: 1.5rem; .initial{ - cursor: pointer; - margin-right: 1rem; - height: 2.2rem; - width: 2.2rem; - flex-shrink: 0; + margin-top: -5.5rem; + margin-bottom: 1rem; + height: 8rem; + width: 8rem; + border-radius: 50%; + font-size: 4rem; + .icon{ + height: 4rem; + width: 4rem; + } } - h4{ + #chat_name{ font-weight: 500; + font-size: 1.2rem; + } + #last_interaction_time{ + color: rgba(var(--text-color), 0.7); font-size: 0.9rem; - } - #receiver_name{ - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + margin-top: 0.5rem; } } - #scroll_to_bottom{ - position: fixed; - right: 0; - bottom: 4rem; - width: 2.6rem; - height: 2.6rem; - padding: 0.9rem; - border-radius: 4rem; - z-index: 1; - margin: 1.5rem; - stroke-width: 8; - cursor: pointer; - transform: scale(0); - transition: transform 0.3s; - } - footer{ - #emoji_toggle{ - align-self: center; - padding: 0.6rem; - width: 2.6rem; - height: 2.6rem; - border-radius: 2rem; - cursor: pointer; - path{ - fill: rgba(var(--text-color), 0.5); - } - &.active path{ - fill: var(--accent-color); - } - } - .flex{ - align-items: flex-end; - padding: 1rem 1rem 1rem 0.4rem; - } - sm-textarea::part(textarea){ - background: rgba(var(--text-color), 0.1); - padding-right: 3rem; - border-radius: 2rem; - } - } - #send_message_button{ - position: absolute; - right: 1.5rem; - transform: scale(0); - opacity: 0; - pointer-events: none; - z-index: 1; - align-self: center; - height: 2.4rem; - width: 2.4rem; - padding: 0.5rem; - cursor: pointer; - stroke: none; - fill: rgba(var(--text-color), 0.4); - margin-left: 1rem; - transition: 0.3s; - &.active{ - opacity: 1; - fill: var(--accent-color); - transform: none; - pointer-events: all; - } - } - #type_message{ - margin: 0; + .copy{ + font-weight: 400; } +} +#chat{ + position: relative; + grid-template-columns: 1fr; .message{ position: relative; - display: grid; - align-items: center; - gap: 0.2rem; - width: 100%; + display: flex; + flex-direction: column; + width: auto; font-size: 0.92rem; max-width: max-content; margin-bottom: 0.2rem; margin-top: 0.8rem; padding: 0.6em 1em; + transition: opacity 0.3s, transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); + .sender-name{ + font-size: 0.85rem; + font-weight: 500; + margin-bottom: 0.3rem; + } .message-body{ - display: inline-flex; + display: flex; align-items: center; flex-wrap: wrap; overflow-wrap: break-word; @@ -1108,7 +1102,7 @@ sm-button[variant="primary"]{ -webkit-hyphens: auto; hyphens: auto; white-space: pre-wrap; - line-height: 1.6; + line-height: 1.5; a{ color: inherit; } @@ -1122,13 +1116,17 @@ sm-button[variant="primary"]{ white-space: nowrap; font-size: 0.8em; opacity: 0.8; + justify-self: flex-end; + padding-left: 1rem; + align-self: flex-end; + margin-top: 0.2rem; } } .sent{ margin-left: auto; + color: #efefef; background: var(--accent-color); - color: #f0f0f0; - border-radius: 1em 0 1em 1em; + border-radius: 0.8rem 0 0.8rem 0.8rem; &::after{ content: ''; position: absolute; @@ -1140,13 +1138,10 @@ sm-button[variant="primary"]{ border-width: 0.5em 0.3em 0 0; border-color: var(--accent-color) transparent transparent transparent; } - .time{ - margin-left: auto; - } } .received{ background: rgba(var(--text-color), 0.1); - border-radius: 0 1em 1em 1em; + border-radius: 0 0.8rem 0.8rem 0.8rem; &::after{ content: ''; position: absolute; @@ -1169,31 +1164,140 @@ sm-button[variant="primary"]{ } .sent + .sent, .received + .received{ - border-radius: 1em; + border-radius: 0.8rem; } .unconfirmed{ opacity: 0.7; - transform-origin: right; - animation: slide-up 0.3s forwards; + transform-origin: left; + animation: pop .3s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); } } -@keyframes slide-up{ - from{ - transform: translateY(-2rem); +@keyframes pop{ + 0%{ + transform: rotate(5deg) translate(-0.5rem, 1rem) } - to{ + 100%{ + transform: rotate(0) translate(0, 0) + } +} +#chat_header{ + padding: 1rem; + min-height: 4rem; + grid-template-columns: auto 1fr auto; + .back-button{ + height: 2rem; + width: 2rem; + padding: 0.5rem; + stroke-width: 8; + margin-right: 0.5rem; + stroke: rgba(var(--text-color), 0.8); + } + .initial{ + cursor: pointer; + margin-right: 1rem; + height: 2.2rem; + width: 2.2rem; + flex-shrink: 0; + } + #receiver_name{ + font-weight: 500; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} +#scroll_to_bottom{ + position: absolute; + display: flex; + right: 0; + bottom: 4rem; + border-radius: 4rem; + z-index: 1; + aspect-ratio: 1/1; + margin: 1.5rem; + cursor: pointer; + transform: scale(0); + transition: transform 0.3s; + &.new-message::after{ + position: absolute; + content: ''; + top: 0; + right: 0; + z-index: 2; + padding: 0.5rem; + border-radius: 50%; + background: #00E676; + } + .icon{ + width: 2.6rem; + height: 2.6rem; + padding: 0.9rem; + stroke-width: 8; + } +} +#chat_footer{ + #emoji_toggle{ + align-self: center; + padding: 0.6rem; + margin-right: 0.5rem; + width: 2.6rem; + height: 2.6rem; + border-radius: 2rem; + cursor: pointer; + path{ + fill: rgba(var(--text-color), 0.5); + } + &.active path{ + fill: var(--accent-color); + } + } + .flex{ + align-items: flex-end; + padding: 1rem 1rem 1rem 0.4rem; + } + sm-textarea::part(textarea){ + padding-right: 3rem; + border-radius: 0.5rem; + } +} +#send_message_button{ + position: absolute; + right: 1.5rem; + transform: scale(0); + opacity: 0; + pointer-events: none; + z-index: 1; + align-self: center; + height: 2.4rem; + width: 2.4rem; + padding: 0.5rem; + cursor: pointer; + stroke: none; + fill: rgba(var(--text-color), 0.4); + margin-left: 1rem; + transition: 0.3s; + &.active{ + opacity: 1; + fill: var(--accent-color); transform: none; + pointer-events: all; } } +#type_message{ + margin: 0; +} .big-emoji{ .message-body{ font-size: 2.6rem; } } -#messages_container{ +#chat_middle{ flex: 1; padding: 0 1rem; } +#messages_container{ + height: 100%; +} #emoji_picker{ display: grid; gap: 1rem; @@ -1217,6 +1321,7 @@ sm-button[variant="primary"]{ background: linear-gradient(rgba(var(--text-color), 0.06), rgba(var(--text-color), 0.06)), rgba(var(--foreground-color), 1); padding: 1rem 0; z-index: 1; + user-select: none; } } .emoji{ @@ -1249,7 +1354,7 @@ sm-button[variant="primary"]{ stroke-width: 16; stroke: rgba(var(--text-color), 0.4); } -#messages_container, +#chat_middle, #chat_container, #inbox_mail_container, #sent_mail_container, @@ -1405,7 +1510,7 @@ sm-panel{ grid-area: illustration; } #main_navbar{ - transform: translateX(-100%); + transform: translateX(-110%); transition: transform 0.3s; z-index: 4; box-shadow: 0 0 1rem rgba(0, 0, 0, 0.3); @@ -1445,17 +1550,6 @@ sm-panel{ } } @media only screen and (min-width: 640px){ - ::-webkit-scrollbar{ - width: 0.5rem; - } - - ::-webkit-scrollbar-thumb{ - background: rgba(var(--text-color), 0.3); - border-radius: 1rem; - &:hover{ - background: rgba(var(--text-color), 0.5); - } - } .hide-on-desktop{ display: none !important; } @@ -1494,10 +1588,12 @@ sm-panel{ width: auto; padding-bottom: 0.5rem; background: rgba(var(--text-color), 0.06); + margin: 0.5rem; + border-radius: 0.8rem; .logo-section{ display: flex; justify-content: center; - margin: 1.5rem 0; + margin: 1rem 0 2rem 0; .main-logo{ margin: 0; } @@ -1530,20 +1626,17 @@ sm-panel{ } #chat{ .message{ - .message-body{ - max-width: 65ch ; - } + width: auto; + align-self: flex-start; + max-width: 55ch; } } #chat_page, #mail_page{ grid-template-columns: 20rem 1fr; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); - z-index: 1; } #settings_page{ display: grid; height: 100vh; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); grid-template-columns: 14rem 1fr; sm-button{ width: max-content; @@ -1568,6 +1661,18 @@ sm-panel{ max-height: 100vh; } } +@media only screen and (max-width: 1280px){ + .hide-on-medium{ + display: none !important; + } +} +@media only screen and (min-width: 1080px){ + #chat{ + #messages_container{ + padding: 1rem 5rem; + } + } +} @media only screen and (min-width: 1280px){ #landing{ gap: 4vw; @@ -1579,29 +1684,57 @@ sm-panel{ #chat_page, #mail_page{ grid-template-columns: 21rem 1fr; } + #chat_details_panel{ + position: relative; + } #chat{ - header{ - padding: 0.8rem 1.5rem; + &.expand-side-panel{ + grid-template-columns: 1fr 24rem; + #messages_container{ + padding: 1rem; + } } - #messages_container{ - padding: 1rem 5rem; + .active{ + background: rgba(var(--text-color), 0.1); } } + .contact.active, + .mail-card.active{ + background: rgba(var(--text-color), 0.06); + } + .card{ + display: inline-flex; + width: auto; + } + #settings_panel{ + overflow-y: auto; + max-height: 100vh; + } } @media (hover: hover){ - .contact:hover, .mail-card:hover, .navbar-item:hover{ - background: rgba(var(--text-color), 0.06); + ::-webkit-scrollbar{ + width: 0.5rem; + } + + ::-webkit-scrollbar-thumb{ + background: rgba(var(--text-color), 0.3); + border-radius: 1rem; + &:hover{ + background: rgba(var(--text-color), 0.5); + } + } + .contact{ cursor: pointer; + .menu{ + opacity: 0; + transition: opacity 0.3s; + } } - .contact .menu{ - opacity: 0; - transition: opacity 0.3s; - } - .contact:hover .menu{ - opacity: 1; - } - .emoji:hover{ - background: rgba(var(--text-color), 0.1); + .contact:hover{ + background: rgba(var(--text-color), 0.06); + .menu{ + opacity: 1; + } } } @media (hover: none){ diff --git a/index.html b/index.html index a77947b..773a71f 100644 --- a/index.html +++ b/index.html @@ -225,12 +225,12 @@ - +
FLO ID
@@ -428,35 +428,75 @@ -
-
- - Go to chat page - - - -
-
-

-
-
-
Messages are not encrypted until receiver replies
-
-
- - - - -
-
-
- - - - +
+
+
+ + Go to chat page + + +
+
+

+
+
+
+
+
Messages are not encrypted until receiver replies
+
+
+
+ + + + +
+
+
+
+
+ + + + + +
+
+
+
+
+ + close + + + +
+
+
+

+

-
+
+

+
+

+ + Copy + + + +
+
+
+

Group description

+

+
+
+

Group members

+
+
+
@@ -724,8 +764,13 @@ switch (e.detail.popup.id) { case 'contact_details_popup': + if(floGlobals.groups[clickedContact.floID]) + getRef("contact_initial").innerHTML = ` + + ` + else + getRef('contact_initial').textContent = clickedContact['name'].charAt(0) getRef('contact_initial').setAttribute('style', `background: ${clickedContact['card'].getAttribute('background-color')}`) - getRef('contact_initial').textContent = clickedContact['name'].charAt(0) getRef('contact_name').textContent = clickedContact['name'] getRef('contact_flo_id').textContent = clickedContact['floID'] break; @@ -903,6 +948,19 @@ } } + function getContactName(floID){ + let name + if(floGlobals.contacts[floID]) + name = floGlobals.contacts[floID] + else if(floGlobals.groups[floID]) + name = floGlobals.groups[floID].name + else if(floID === myFloID) + name = 'You' + else + name = floID + return name + } + function areInputsValid(parent) { let allInputs = parent.querySelectorAll("sm-input:not([disabled])"), inputsFilled = [...allInputs].every(input => { @@ -1107,12 +1165,13 @@ //clear Rendered Elements let elementsToReset = ['inbox_mail_container', 'sent_mail_container', 'contacts_container', 'chat_container', 'messages_container', 'receiver_name', 'mail_contact_list' - ] + ] //, "backup_info" elementsToReset.forEach(e => clearElement(getRef(e))) - + floDapps.setCustomPrivKeyInput(signIn) - + + chatMutationObserver.observe(getRef('messages_container'), {childList: true, subtree: true}) //invoke the startup functions floDapps.launchStartUp().then(result => { console.log(result) @@ -1174,7 +1233,6 @@ // render elements const render = { mailCard(floID, ref, subject, timestamp, content, markUnread){ - console.log(timestamp) let card = getRef('mail_card_template').content.cloneNode(true), cardContainer = card.firstElementChild let mailSummery = content.split(' ') @@ -1229,28 +1287,35 @@ card.querySelector('.mail-content').textContent = content return card }, - async contactCard(floID, name, type, options = {}){ - let {prepend = false, markUnread = false} = options + contactCard(floID, options = {}){ + let {name, type, prepend = false, markUnread = false, contactOnly = false} = options let card = getRef('contact_template').content.cloneNode(true), cardContainer = card.firstElementChild - cardContainer.setAttribute("name", name || 'Unknown') + if(!name) + name = getContactName(floID) + + cardContainer.setAttribute("name", name) cardContainer.setAttribute("flo-id", floID) - cardContainer.querySelector('.name').textContent = name || floID let initial = card.querySelector('.initial') let color = contactColor(floID) - //cardContainer.setAttribute("text-color", randomColor.primary) + if(type === 'group'){ initial.innerHTML = ` ` + cardContainer.querySelector('.name').textContent = floGlobals.groups[floID].name } else{ - initial.textContent = name ? name.charAt(0) : floID.charAt(0) + cardContainer.querySelector('.name').textContent = name !== 'Unknown' ? name : floID + initial.textContent = name !== 'Unknown' ? name.charAt(0) : floID.charAt(0) } cardContainer.setAttribute("background-color", color) initial.setAttribute(`style`, `background-color: ${color};`) - if(type === 'contact'){ - cardContainer.classList.add('contact') + + if(contactOnly){ + return card; + } + else if(type === 'contact'){ let duplicateCard = card.cloneNode(true); getRef('contacts_container').append(card); getRef('mail_contact_list').append(duplicateCard); @@ -1266,13 +1331,21 @@ messenger.getChat(floID).then(chat => { let lastMessage = {message: '', time: 0} if(Object.values(chat).length){ - lastMessage = Object.values(chat).pop() + for(msg of Object.values(chat).reverse()){ + if(msg.message){ + lastMessage = msg + break; + } + } } else if(type === 'group'){ lastMessage.time = floGlobals.groups[floID].created } + let lastText = document.createElement('p') + lastText.textContent = lastMessage.message + lastText.classList.add('last-message') + cardContainer.append(lastText) cardContainer.innerHTML += ` -

${lastMessage.message}

${getFormatedTime(lastMessage.time, true)}
@@ -1283,66 +1356,123 @@ .catch(error => console.error(error)) if(prepend){ getRef('chat_container').prepend(card); - getRef('chat_container').children[0].click() + activeChat['receiver'] = floID + if(activeChat['chatCard']) + activeChat['chatCard'].classList.remove('active') + getRef('chat_container').children[0].classList.add('active') + activeChat['chatCard'] = getRef('chat_container').children[0] } else{ getRef('chat_container').append(card); } } }, - messageBubble(floID, message, timestamp, category, unconfirmed = false){ + messageBubble(msg){ + let {admin = false, newMembers = [], groupID, name, sender, floID, message, time: timestamp, category, unconfirmed = false, updateChatCard = false} = msg let card = getRef('message_template').content.cloneNode(true), - cardContainer = card.querySelector('.message') + cardContainer = card.querySelector('.message'), + messageContent = cardContainer.children[0], + messageTime = cardContainer.children[1] - cardContainer.id = `${floID}_${timestamp}` - if(unconfirmed) - cardContainer.classList.add('unconfirmed') - - cardContainer.classList.add(category) - if(isValidUrl(message)){ - const anchorTag = document.createElement('a') - anchorTag.href = message - anchorTag.target="_blank" - anchorTag.textContent = message - cardContainer.children[0].append(anchorTag) - } - else{ - let [messageBody, isOnlyEmoji] = isEmoji(message) - if(isOnlyEmoji) - cardContainer.classList.add('big-emoji') - cardContainer.children[0].append(messageBody) + if(activeChat.isGroup){ + floID = groupID + category = sender === myFloID ? 'sent': 'received' } - let time = new Date(timestamp).toString(), - minutes = String(new Date(timestamp).getMinutes()), - hours = new Date(timestamp).getHours(), - year = new Date(timestamp).getFullYear() - minutes = minutes.length === 1 ? `0${minutes}` : minutes - let finalHours = hours - 12 > 0 ? `${hours - 12}:${minutes} pm` : `${hours}:${minutes} am` - - cardContainer.children[1].textContent = finalHours - - if(currentFloID !== floID){ - currentDate = null - currentFloID = floID - renderedDates.clear() + if(message){ + cardContainer.id = `${floID}_${timestamp}` + if(unconfirmed) + cardContainer.classList.add('unconfirmed') + + cardContainer.classList.add(category) + + if(sender){ + if(sender !== myFloID && lastSender !== sender){ + let senderName = document.createElement('div') + senderName.classList.add('sender-name') + senderName.style.color = contactColor(sender) + senderName.textContent = getContactName(sender) + cardContainer.prepend(senderName) + + messageContent = cardContainer.children[1] + messageTime = cardContainer.children[2] + } + lastSender = sender + } + + if(isValidUrl(message)){ + const anchorTag = document.createElement('a') + anchorTag.href = message + anchorTag.target="_blank" + anchorTag.rel="noopener" + anchorTag.textContent = message + messageContent.append(anchorTag) + } + else{ + let [messageBody, isOnlyEmoji] = isEmoji(message) + if(isOnlyEmoji) + cardContainer.classList.add('big-emoji') + messageContent.append(messageBody) + } + let time = new Date(timestamp).toString(), + minutes = String(new Date(timestamp).getMinutes()), + hours = new Date(timestamp).getHours(), + year = new Date(timestamp).getFullYear() + minutes = minutes.length === 1 ? `0${minutes}` : minutes + let finalHours = hours - 12 > 0 ? `${hours - 12}:${minutes} pm` : `${hours}:${minutes} am` + + messageTime.textContent = finalHours + if(currentFloID !== floID){ + currentDate = null + lastSender = null + currentFloID = floID + renderedDates.clear() + } + + if(!renderedDates.has(`${time.slice(4, 10)} ${year}`) && `${time.slice(4, 10)} ${year}` !== currentDate){ + let dateCard = document.createElement('h5') + dateCard.classList.add('date-card') + dateCard.textContent = new Date().getFullYear() !== year ? `${time.slice(4, 10)} ${year}` : time.slice(4, 10) + currentDate = `${time.slice(4, 10)} ${year}` + let frag = document.createDocumentFragment() + frag.append(dateCard, card) + renderedDates.set(currentDate, currentDate) + return frag + } + else + return card; + } + else if(admin){ + if(newMembers.length){ + const cards = document.createDocumentFragment() + const {admin} = floGlobals.groups[groupID] + newMembers.forEach(member => { + let eventCard = document.createElement('p') + eventCard.classList.add('group-event-card') + let eventMessage = '' + if(member === myFloID) + eventMessage = `${getContactName(admin)} added you` + else + eventMessage = `${getContactName(admin)} added ${member}` + eventCard.textContent = eventMessage + cards.append(eventCard) + }) + return cards + } + else if(name){ + let eventCard = document.createElement('p') + eventCard.classList.add('group-event-card') + eventCard.textContent = `Changed group name to '${name}'` + return eventCard + } } - if(!renderedDates.has(`${time.slice(4, 10)} ${year}`) && `${time.slice(4, 10)} ${year}` !== currentDate){ - let dateCard = document.createElement('h5') - dateCard.classList.add('date-card') - dateCard.textContent = new Date().getFullYear() !== year ? `${time.slice(4, 10)} ${year}` : time.slice(4, 10) - currentDate = `${time.slice(4, 10)} ${year}` - let frag = document.createDocumentFragment() - frag.append(dateCard, card) - renderedDates.set(currentDate, currentDate) - return frag - } - else - return card; }, } - let currentDate, currentFloID, renderedDates = new Map() + let currentDate, + currentFloID, + renderedDates = new Map(), + lastSender const isValidUrl = (url) => { try { @@ -1389,16 +1519,17 @@ notify(`${Object.keys(data.mails).length} new mail(s)`) } } - + function renderGroupUI(data){ - console.log(data) + renderMessages(data.messages, {updateChatCard: true}); } window.addEventListener('focus', e => { - if(activeChat.chatCard && activeChat.chatCard.classList.contains('active')) - setTimeout(() => { - activeChat.chatCard.classList.remove('unread') - }, 2000) + if(activeChat.chatCard){ + if(!chatScrollInfo.isScrolledUp){ + scrollToBottom() + } + } }) window.addEventListener('blur', e => { console.log('blured') @@ -1462,16 +1593,16 @@ }) const chatScrollInfo = {}; - getRef('messages_container').addEventListener('scroll', function() { + getRef('chat_middle').addEventListener('scroll', function() { chatScrollInfo['scrollTop'] = this.scrollTop chatScrollInfo['scrollheight'] = this.scrollHeight if((this.scrollHeight > this.clientHeight) && (this.scrollHeight - this.clientHeight - this.scrollTop >= 100)){ - chatScrollInfo['scrolledUp'] = true + chatScrollInfo['isScrolledUp'] = true getRef('scroll_to_bottom').classList.add('no-transformations') } else{ - chatScrollInfo['scrolledUp'] = false - getRef('scroll_to_bottom').classList.remove('no-transformations') + chatScrollInfo['isScrolledUp'] = false + getRef('scroll_to_bottom').classList.remove('no-transformations', 'new-message') } }, {passive: true}) @@ -1508,10 +1639,6 @@ if(target.dataset.target) showPanel(target, target.dataset.target) } - else if(e.target.closest('.contact') && e.target.closest('#mail_contact_list')){ - getRef('send_mail_to').value = e.target.closest('.contact').getAttribute('flo-id') - getRef('mail_contact_list').classList.add('hide-completely') - } if(e.target.closest('.navbar-item') && activePage.button !== e.target.closest('.navbar-item')){ let targetButton = e.target.closest('.navbar-item'), targetPage = getRef(targetButton.dataset.target) @@ -1570,34 +1697,45 @@ isEmojiPickerOpen = false getRef('emoji_toggle').classList.remove('active') getRef('emoji_picker').classList.add('hide-completely') - getRef('scroll_to_bottom').setAttribute('style', `top: calc(${getRef('messages_container').getBoundingClientRect().height}px - 1.5rem`) - if(!chatScrollInfo.scrolledUp) + if(!chatScrollInfo.isScrolledUp) scrollToBottom() } }) - let mygroup = []; + getRef('mail_contact_list').addEventListener('click', e => { + if(e.target.closest('.contact')){ + getRef('send_mail_to').value = e.target.closest('.contact').getAttribute('flo-id') + getRef('mail_contact_list').classList.add('hide-completely') + } + }) + let clickedContact = {} - getRef('contacts').addEventListener('click', e => { + + let selectedGroupMembers = new Set() + + getRef('chat_page').addEventListener('click', e => { //detect click on chat cards if (e.target.closest(".contact")){ - const contact = e.target.closest(".contact") + let contact = e.target.closest(".contact") clickedContact['card'] = contact clickedContact['floID'] = contact.getAttribute("flo-id") clickedContact['name'] = contact.getAttribute("name") - if(e.target.closest(".initial") || e.target.closest(".icon")){ + if(clickedContact['floID'] === myFloID) return + if(e.target.closest(".initial") || e.target.closest(".menu")){ showPopup('contact_details_popup') } else if(isCreatingGroup){ - selectContact(contact); - // console.log(mygroup) - + // code for adding group members + selectContact(contact) } else{ createRipple(e, contact) + if(!contact.closest('chat_container')) + contact = getRef('chat_container').querySelector(`[flo-id="${clickedContact['floID']}"]`) contact.classList.remove('unread') if(activeChat['chatCard'] === contact && window.innerWidth > 640) return + showChatDetails(false) document.title = `FLO Messenger` getRef('chat').classList.remove('hide-completely') viewConversation(contact) @@ -1614,73 +1752,57 @@ } } }) + function selectContact(contact){ - if(!mygroup.includes(clickedContact.floID)){ - - let selectedContact = clickedContact['card'].querySelector('.initial').cloneNode(true); - let selectedContactsContainer = getRef('selected_contacts_container'); - - selectedContact.setAttribute('floID' , clickedContact['floID'] ); - selectedContact.onclick = removeContactCard; - - - // creating close icon - let closeIcon = createClose(); - - - // creating tick icon - let tickIcon = createTick(); - - - // adding animation to contactCard - let animatingCard = addAnimate(); - - mygroup.push(clickedContact['floID']); - selectedContactsContainer.appendChild(selectedContact); - selectedContact.appendChild(closeIcon); - selectedContact.animate(animatingCard[0], animatingCard[1]); - - selectedContactsContainer.style.display = "flex"; - selectedContactsContainer.style.flexWrap = "wrap"; - selectedContactsContainer.style.maxHeight = "70px"; - selectedContactsContainer.style.overflow = "auto"; - selectedContact.style.margin = "8px"; - selectedContact.style.cursor = "pointer"; - clickedContact['card'].querySelector('.initial').appendChild(tickIcon); - tickIcon.animate(animatingCard[0], animatingCard[1]); - - - } - - + if(!selectedGroupMembers.has(clickedContact.floID)){ - else{ - let selectedContactsContainer = getRef('selected_contacts_container'); - let removeIndex = mygroup.indexOf(clickedContact['floID']); - let removeContact = selectedContactsContainer.querySelector('div:nth-of-type('+ (removeIndex + 1)+ ')'); - let tickIcon = clickedContact['card'].querySelector('.initial').querySelector('img'); - let animatingCardRemove = removeAnimate(); + let selectedContact = clickedContact['card'].querySelector('.initial').cloneNode(true); + let selectedContactsContainer = getRef('selected_contacts_container'); + + selectedContact.setAttribute('floID' , clickedContact['floID'] ); + selectedContact.onclick = removeContactCard; + + // adding animation to contactCard + let animatingCard = addAnimate(); + + mygroup.push(clickedContact['floID']); + selectedContactsContainer.appendChild(selectedContact); + selectedContact.appendChild(closeIcon); + selectedContact.animate(animatingCard[0], animatingCard[1]); + + selectedContact.style.margin = "8px"; + selectedContact.style.cursor = "pointer"; + clickedContact['card'].querySelector('.initial').appendChild(tickIcon); + tickIcon.animate(animatingCard[0], animatingCard[1]); + } + + else{ + let selectedContactsContainer = getRef('selected_contacts_container'); + let removeIndex = mygroup.indexOf(clickedContact['floID']); + let removeContact = selectedContactsContainer.querySelector('div:nth-of-type('+ (removeIndex + 1)+ ')'); + let tickIcon = clickedContact['card'].querySelector('.initial').querySelector('img'); + let animatingCardRemove = removeAnimate(); - if(removeIndex > -1){ - mygroup.splice(removeIndex,1); - } - - removeContact.animate(animatingCardRemove[0],animatingCardRemove[1]); - tickIcon.animate(animatingCardRemove[0], animatingCardRemove[1]); - - setTimeout( function(){ - - removeContact.remove(); - tickIcon.remove(); - - },300) + if(removeIndex > -1){ + mygroup.splice(removeIndex,1); } + removeContact.animate(animatingCardRemove[0],animatingCardRemove[1]); + tickIcon.animate(animatingCardRemove[0], animatingCardRemove[1]); + + setTimeout( function(){ + + removeContact.remove(); + tickIcon.remove(); + + },300) + } + } - + let mygroup = [] function clearAllMember(){ mygroup=[]; let selectedContactsContainer = getRef('selected_contacts_container'); @@ -1696,38 +1818,6 @@ } - - - function createClose(){ - - let closeIcon = document.createElement('img'); - closeIcon.src = "assets/close.svg"; - closeIcon.style.width = "20px"; - closeIcon.style.background = "#fff"; - closeIcon.style.borderRadius = "50%"; - closeIcon.style.position = "absolute"; - closeIcon.style.marginTop = "32px"; - closeIcon.style.marginLeft = "32px"; - - return closeIcon; - - } - - function createTick(){ - - let tickIcon = document.createElement('img'); - tickIcon.src = "assets/tick.svg"; - tickIcon.style.width = "20px"; - tickIcon.style.background = "#fff"; - tickIcon.style.borderRadius = "50%"; - tickIcon.style.position = "absolute"; - tickIcon.style.marginTop = "32px"; - tickIcon.style.marginLeft = "32px"; - - return tickIcon; - - } - function removeContactCard(){ let contactFloID = this.getAttribute("floID"); let removeIndex = mygroup.indexOf(contactFloID); @@ -1745,63 +1835,12 @@ setTimeout(function(){ - + removeCard.remove(); tickIcon.remove(); - },300) - } - function addAnimate(){ - const animation = [ - { - transform : "scale(0)", - opacity: 0.2 - }, - - { - transform : "none", - opacity:1 - - } - ] - - const options = { - duration : 300, - iterations : 1, - easing : "linear" - - }; - - return [animation,options]; - - } - - - function removeAnimate(){ - const animation = [ - { - transform : "none", - opacity:1 - }, - - { - transform : "scale(0)", - opacity: 0.2 - } - ] - - const options = { - duration : 300, - iterations : 1, - easing : "linear" - - }; - - return [animation,options]; - - } const emojis = [ "<", "๐Ÿ˜€", "๐Ÿ˜ƒ", "๐Ÿ˜„", "๐Ÿ˜", "๐Ÿ˜†", "๐Ÿ˜…", "๐Ÿ˜‚", "๐Ÿคฃ", "๐Ÿ˜Š", "๐Ÿ˜‡", "๐Ÿ™‚", "๐Ÿ™ƒ", "๐Ÿ˜‰", "๐Ÿ˜Œ", "๐Ÿ˜", "๐Ÿฅฐ", "๐Ÿ˜˜", "๐Ÿ˜—","๐Ÿ˜™", "๐Ÿ˜š", "๐Ÿ˜‹", "๐Ÿ˜›", "๐Ÿ˜", "๐Ÿ˜œ", "๐Ÿคช", "๐Ÿคจ", "๐Ÿง", @@ -1888,12 +1927,11 @@ function toggleEmoji(button){ getRef('emoji_toggle').classList.toggle('active') getRef('emoji_picker').classList.toggle('hide-completely') - getRef('scroll_to_bottom').setAttribute('style', `top: calc(${getRef('messages_container').getBoundingClientRect().height}px - 1.5rem`) if(getRef('emoji_picker').classList.contains('hide-completely')) isEmojiPickerOpen = false else isEmojiPickerOpen = true - if(!chatScrollInfo.scrolledUp) + if(!chatScrollInfo.isScrolledUp) scrollToBottom() } @@ -2131,8 +2169,16 @@ getRef('type_message').value = '' if(message === '') return let time = Date.now() - getRef('messages_container').append(render.messageBubble(receiver, message, time, 'sent', true)) - scrollToBottom(true) + let msgObj = {message, time, unconfirmed: true} + if(activeChat.isGroup){ + msgObj['groupID'] = activeChat.receiver + msgObj['sender'] = myFloID + } + else{ + msgObj['floID'] = activeChat.receiver + msgObj['category'] = 'sent' + } + getRef('messages_container').append(render.messageBubble(msgObj)) const contact = getRef('chat_container').querySelector(`.chat[flo-id="${receiver}"], .group[flo-id="${receiver}"]`) if(contact){ if(activeChat['chatCard'] !== getRef('chat_container').children[0]){ @@ -2141,7 +2187,7 @@ activeChat['chatCard'] = cloneContact getRef('chat_container').prepend(cloneContact) animateTo(getRef('chat_container').children[0], [ - {transform: 'translateY(1rem)'}, + {transform: 'translateY(1rem)'}, {transform: 'none'}, ], { @@ -2153,16 +2199,17 @@ } else{ messenger.addChat(receiver) - render.contactCard(receiver, floGlobals.contacts[receiver], 'chat', {prepend: true}) + render.contactCard(receiver, {type: 'chat', prepend: true}) } + scrollToBottom() if(activeChat.isGroup) messenger.sendGroupMessage(message, receiver).then(data => { console.log('sent group message') getRef('messages_container').querySelector(`#${receiver}_${time}`).classList.remove('unconfirmed') - activeChat.chatCard.querySelector('.last-message').textContent = message + activeChat.chatCard.querySelector('.last-message').textContent = `You: ${message}` activeChat.chatCard.querySelector('.time').textContent = getFormatedTime(Date.now(), true) }).catch(error => notify(error, "error")); - else + else messenger.sendMessage(message, receiver).then(data => { getRef('messages_container').querySelector(`#${receiver}_${time}`).classList.remove('unconfirmed') activeChat.chatCard.querySelector('.last-message').textContent = message @@ -2191,7 +2238,7 @@ return } messenger.storeContact(floID, name).then(result => { - render.contactCard(floID, name, 'contact') + render.contactCard(floID, {name, type: 'contact'}) hidePopup() notify(`Added Contact: ${floID}`) }).catch(error => notify(error, "error")); @@ -2199,7 +2246,7 @@ function renderContactList(contactList = {}) { for (floID in contactList) - render.contactCard(floID, contactList[floID], 'contact') + render.contactCard(floID, {type: 'contact'}) } async function renderChatList() { @@ -2211,9 +2258,8 @@ type = 'chat' else if(floGlobals.groups[floID]) type = 'group' - render.contactCard(floID, floGlobals.contacts[floID], type, {markUnread}) + render.contactCard(floID, {type, markUnread}) } - chatMutationObserver.observe(getRef('messages_container'), {childList: true}) } function renderMarked(data) { @@ -2224,8 +2270,13 @@ } } - function scrollToBottom(smooth = false){ - getRef('messages_container').scrollTo({top: getRef('messages_container').scrollHeight, behaviour: smooth ? 'smooth': ''}) + function scrollToBottom(){ + if(activeChat.chatCard){ + messenger.removeMark(activeChat.receiver, 'unread') + activeChat.chatCard.classList.remove('unread') + } + getRef('scroll_to_bottom').classList.remove('new-message') + getRef('chat_middle').scrollTo(0, getRef('chat_middle').scrollHeight) } let startIndex = 0, @@ -2235,62 +2286,95 @@ let messages if(reRender){ activeChat['allMessages'] = Object.values(data) - startIndex = (activeChat['allMessages'].length - 20) > 0 ? activeChat['allMessages'].length - 20 : 0 + startIndex = activeChat['allMessages'].length > 20 ? activeChat['allMessages'].length - 20 : 0 endIndex = activeChat['allMessages'].length messages = activeChat['allMessages'] renderedDates.clear() } else if(lazyLoad){ messages = activeChat['allMessages'] - startIndex = startIndex > 20 ? startIndex -= 20 : 0 + endIndex = startIndex + startIndex = endIndex > 20 ? endIndex - 20 : 0 markUnread = false } else{ messages = Object.values(data) - startIndex = 0 - endIndex = messages.length + if(messages.length){ + startIndex = 0 + endIndex = messages.length + } } - for (i = startIndex; i < endIndex; i++) { - let {floID, message, time, category} = messages[i] - //Stops message from rendering in wrong chat window - if(activeChat['receiver'] && activeChat['receiver'] === floID) - frag.append(render.messageBubble(floID, message, time, category)) - const contact = getRef('chat_container').querySelector(`.chat[flo-id='${floID}']`) - if (markUnread && contact){ - contact.classList.add("unread"); - if(contact !== getRef('chat_container').children[0]){ - const cloneContact = contact.cloneNode(true) - contact.remove() - getRef('chat_container').prepend(cloneContact) - animateTo(getRef('chat_container').children[0], [ - {transform: 'translateY(1rem)'}, - {transform: 'none'}, - ], - { - easing: 'ease', - duration: 300 - } - ) + if(messages && messages.length){ + for (let i = startIndex; i < endIndex; i++) { + let {floID, groupID, sender, message, time, category} = messages[i] + //Stops message from rendering in wrong chat window + if(activeChat['receiver'] && ( activeChat['receiver'] === floID || activeChat['receiver'] === groupID)){ + if(updateChatCard && activeChat.isGroup && message && sender === myFloID) return + frag.append(render.messageBubble({...messages[i], updateChatCard})) } - } - if(updateChatCard){ - const chatCard = getRef('chat_container').querySelector(`[flo-id="${floID}"]`) - chatCard.querySelector('.last-message').textContent = message - chatCard.querySelector('.time').textContent = getFormatedTime(time, true) - } - } - endIndex = startIndex + const contact = getRef('chat_container').querySelector(`.chat[flo-id='${floID}']`) + if (markUnread && contact){ + contact.classList.add("unread"); + if(contact !== getRef('chat_container').children[0]){ + const cloneContact = contact.cloneNode(true) + contact.remove() + getRef('chat_container').prepend(cloneContact) + animateTo(getRef('chat_container').children[0], [ + {transform: 'translateY(1rem)'}, + {transform: 'none'}, + ], + { + easing: 'ease', + duration: 300 + } + ) + } + } + if(updateChatCard){ + const chatCard = getRef('chat_container').querySelector(`.contact[flo-id="${floID || groupID}"]`) + let finalMessage + if(floGlobals.contacts[sender]) + finalMessage = `${floGlobals.contacts[sender]}: ${message}` + else if(sender === myFloID) + finalMessage = `You: ${message}` + else + finalMessage = message + chatCard.querySelector('.last-message').textContent = finalMessage + chatCard.querySelector('.time').textContent = getFormatedTime(time, true) + + if(activeChat.receiver === (floID || groupID)){ + if(chatScrollInfo.isScrolledUp) + getRef('scroll_to_bottom').classList.add('new-message') + else{ + if(document.hasFocus()){ + messenger.removeMark((floID || groupID), 'unread') + setTimeout(() => { + document.title = 'FLO Messenger' + activeChat.chatCard.classList.remove('unread') + }, 1000); + } + } + } + if(!document.hasFocus() && navigator.onLine) { + getRef('notification_sound').currentTime = 0; + getRef('notification_sound').play(); + } + } + } + } + if(!lazyLoad && !reRender){ endIndex = messages.length getRef('messages_container').append(frag) - if(!chatScrollInfo['scrolledUp']) + if(!chatScrollInfo['isScrolledUp']) scrollToBottom() } if(reRender || lazyLoad){ currentDate = null - chatScrollInfo['scrollTop'] = getRef('messages_container').scrollTop - chatScrollInfo['scrollHeight'] = getRef('messages_container').scrollHeight + lastSender = null + chatScrollInfo['scrollTop'] = getRef('chat_middle').scrollTop + chatScrollInfo['scrollHeight'] = getRef('chat_middle').scrollHeight getRef('messages_container').prepend(frag) } if(reRender){ @@ -2302,11 +2386,11 @@ const chatMutationObserver = new MutationObserver( (mutations, observer) => { for(const mutation of mutations) { - if (mutation.type === 'childList' && mutation.addedNodes.length) { + if (mutation.type === 'childList' && mutation.addedNodes.length && getRef('messages_container').firstElementChild) { chatMessageObserver.observe(getRef('messages_container').firstElementChild) - chatScrollInfo['scrollTop'] += (getRef('messages_container').scrollHeight - chatScrollInfo['scrollHeight']) - chatScrollInfo['scrollHeight'] = getRef('messages_container').scrollHeight - getRef('messages_container').scrollTo({top: chatScrollInfo['scrollTop']}) + chatScrollInfo['scrollTop'] += (getRef('chat_middle').scrollHeight - chatScrollInfo['scrollHeight']) + chatScrollInfo['scrollHeight'] = getRef('chat_middle').scrollHeight + getRef('chat_middle').scrollTo({top: chatScrollInfo['scrollTop']}) } } } @@ -2328,18 +2412,47 @@ name = contact.getAttribute('name'), textColor = contact.getAttribute('text-color'), backgroundColor = contact.getAttribute('background-color') + activeChat['receiver'] = floID + getRef("chat_flo_id").textContent = floID activeChat['isGroup'] = floGlobals.groups[floID] ? true : false if(activeChat.isGroup){ getRef("receiver_initial").innerHTML = ` ` + getRef("chat_dp").innerHTML = ` + + ` + getRef("receiver_name").textContent = floGlobals.groups[floID].name; + getRef("chat_name").textContent = floGlobals.groups[floID].name; + getRef("last_interaction_time").textContent = `Created ${getFormatedTime(floGlobals.groups[floID].created)}`; + + getRef("chat_type").textContent = `Group FLO ID`; + + getRef('group_members_list').innerHTML = '' + floGlobals.groups[floID].members.forEach(member => { + frag.append(render.contactCard(member, {type: 'contact', contactOnly: true})) + }) + getRef('group_members_list').append(frag) + + getRef("group_description_card").classList.remove('hide-completely') + getRef("group_members_card").classList.remove('hide-completely') + getRef("group_description").textContent = floGlobals.groups[floID].description; } else{ - getRef("receiver_initial").textContent = floGlobals.contacts[floID] ? floGlobals.contacts[floID].charAt(0) : name.charAt(0) || ' '; + getRef("receiver_initial").textContent = getContactName(floID).charAt(0); + getRef("chat_dp").textContent = getContactName(floID).charAt(0); + getRef("receiver_name").textContent = getContactName(floID); + getRef("chat_name").textContent = getContactName(floID); + getRef("last_interaction_time").textContent = ``; + + getRef("chat_type").textContent = `FLO ID`; + + getRef("group_description_card").classList.add('hide-completely') + getRef("group_members_card").classList.add('hide-completely') } getRef("receiver_initial").setAttribute('style', `color: ${textColor}; background-color: ${backgroundColor};`) - getRef("receiver_name").textContent = floGlobals.contacts[floID] || floID || ' '; + getRef("chat_dp").setAttribute('style', `color: ${textColor}; background-color: ${backgroundColor};`) if (floGlobals.pubKeys[floID] || activeChat.isGroup) getRef("warn_no_encryption").classList.add("hide-completely"); else @@ -2347,7 +2460,7 @@ renderMessages(await messenger.getChat(floID),{markUnread: false, reRender: true}) messenger.removeMark(floID, "unread"); if(this.scrollHeight <= this.clientHeight){ - chatScrollInfo['scrolledUp'] = false + chatScrollInfo['isScrolledUp'] = false getRef('scroll_to_bottom').classList.remove('no-transformations') } } @@ -2592,6 +2705,31 @@ getRef(target).children[1].focusIn() } + function showChatDetails(show){ + if(show){ + getRef('chat').classList.add('expand-side-panel') + getRef('chat_left').classList.add('hide-on-medium') + getRef('chat_details_panel').classList.remove('hide-completely') + } + else{ + getRef('chat').classList.remove('expand-side-panel') + getRef('chat_left').classList.remove('hide-on-medium') + getRef('chat_details_panel').classList.add('hide-completely') + } + } + + async function deleteChat(){ + if(await confirmation('Delete chat?', `Are you sure to delete this chat?`, 'No', "Yes")){ + messenger.rmChat(clickedContact.floID).then(result => { + clickedContact.card.remove() + clickedContact.card = '' + hidePopup() + getRef('chat').classList.add('hide-completely') + notify('Chat deleted', 'success') + }) + } + } +