Feature update and bug fixes

-- added UI for multisig creation
This commit is contained in:
sairaj mote 2022-08-24 17:05:55 +05:30
parent 19a83a9035
commit 71b2f2557c
5 changed files with 2976 additions and 2459 deletions

View File

@ -39,7 +39,7 @@ body {
--orange: #ff9100; --orange: #ff9100;
--redish-orange: #ff3d00; --redish-orange: #ff3d00;
color: rgba(var(--text-color), 1); color: rgba(var(--text-color), 1);
background: rgba(var(--foreground-color), 1); background: rgba(var(--background-color), 1);
overflow-y: hidden; overflow-y: hidden;
} }
body #scroll_to_bottom { body #scroll_to_bottom {
@ -91,14 +91,19 @@ strong {
color: rgba(var(--text-color), 0.9); color: rgba(var(--text-color), 0.9);
} }
.warning { .info {
line-height: normal; line-height: normal;
padding: 1rem; padding: 1rem;
background-color: khaki;
border-radius: 0.5rem; border-radius: 0.5rem;
font-weight: 500; font-weight: 500;
color: rgba(0, 0, 0, 0.7); color: rgba(0, 0, 0, 0.7);
} }
.info--warning {
background-color: khaki;
}
.info--error {
background-color: var(--danger-color);
}
a { a {
text-decoration: none; text-decoration: none;
@ -120,7 +125,6 @@ button,
.button { .button {
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
position: relative; position: relative;
display: inline-flex; display: inline-flex;
@ -164,6 +168,10 @@ button:not(:disabled),
.button--small { .button--small {
padding: 0.4rem 0.6rem; padding: 0.4rem 0.6rem;
} }
.button--outlined {
border: solid rgba(var(--text-color), 0.5) 0.1rem;
background-color: rgba(var(--foreground-color), 1);
}
.cta { .cta {
text-transform: uppercase; text-transform: uppercase;
@ -207,7 +215,6 @@ details summary {
display: flex; display: flex;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
@ -241,7 +248,7 @@ sm-copy {
sm-input, sm-input,
sm-textarea { sm-textarea {
font-size: 0.9rem; font-size: 0.9rem;
--border-radius: 0.3rem; --border-radius: 0.5rem;
--background-color: rgba(var(--foreground-color), 1); --background-color: rgba(var(--foreground-color), 1);
} }
sm-input button .icon, sm-input button .icon,
@ -298,7 +305,6 @@ strip-option {
--border-radius: 0.2rem; --border-radius: 0.2rem;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
} }
@ -359,7 +365,6 @@ ol li::before {
word-wrap: break-word; word-wrap: break-word;
word-break: break-word; word-break: break-word;
-webkit-hyphens: auto; -webkit-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto; hyphens: auto;
} }
@ -972,10 +977,10 @@ sm-button[variant=primary] {
.initial { .initial {
position: relative; position: relative;
justify-content: center; justify-content: center;
font-size: 1.2rem; font-size: 1.1rem;
font-weight: 500; font-weight: 700;
width: 2.8rem; width: 2.4rem;
height: 2.8rem; height: 2.4rem;
aspect-ratio: 1/1; aspect-ratio: 1/1;
color: rgba(var(--foreground-color), 1); color: rgba(var(--foreground-color), 1);
box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.06); box-shadow: 0 0.1rem 0.1rem rgba(0, 0, 0, 0.06);
@ -983,9 +988,21 @@ sm-button[variant=primary] {
text-transform: uppercase; text-transform: uppercase;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
overflow: hidden;
background-color: var(--contact-color, --accent-color); background-color: var(--contact-color, --accent-color);
flex-shrink: 0;
}
.initial::after {
content: "";
position: absolute;
background-color: rgba(255, 255, 255, 0.2);
width: 100%;
height: 200%;
margin-left: 50%;
margin-top: 50%;
transform: rotate(45deg);
transform-origin: left center;
} }
.group-icon { .group-icon {
@ -998,12 +1015,10 @@ sm-button[variant=primary] {
position: relative; position: relative;
display: grid; display: grid;
gap: 0 1rem; gap: 0 1rem;
padding: 0.8rem 1.5rem;
align-items: center; align-items: center;
flex-shrink: 0; flex-shrink: 0;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
overflow: hidden; overflow: hidden;
} }
@ -1035,6 +1050,7 @@ sm-button[variant=primary] {
width: 100%; width: 100%;
font-size: 1em; font-size: 1em;
font-weight: 500; font-weight: 500;
margin-bottom: 0.3rem;
} }
.contact .span-2 { .contact .span-2 {
display: flex; display: flex;
@ -1046,6 +1062,7 @@ sm-button[variant=primary] {
.contact .last-message { .contact .last-message {
font-weight: 400; font-weight: 400;
font-size: 0.9em; font-size: 0.9em;
opacity: 0.9;
} }
.contact .menu { .contact .menu {
justify-self: flex-end; justify-self: flex-end;
@ -1067,11 +1084,16 @@ sm-button[variant=primary] {
} }
.selectable-contact { .selectable-contact {
margin: 0 -0.3rem;
padding: 0.5rem 0.3rem;
border-radius: 0.5rem;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
} }
.selectable-contact:not(:last-of-type) {
margin-bottom: 0.2rem;
}
.selectable-contact input { .selectable-contact input {
margin-left: auto; margin-left: auto;
} }
@ -1081,6 +1103,7 @@ sm-button[variant=primary] {
align-items: center; align-items: center;
} }
.group-member .admin-tag { .group-member .admin-tag {
white-space: nowrap;
margin-left: auto; margin-left: auto;
padding: 0.1rem 0.6rem; padding: 0.1rem 0.6rem;
font-size: 0.8rem; font-size: 0.8rem;
@ -1194,18 +1217,24 @@ sm-button[variant=primary] {
} }
#warn_no_encryption { #warn_no_encryption {
background: #fffd8d; background: rgb(255, 253, 141);
color: #111; color: #111;
} }
.contact .initial::after, .contact,
.mail-card .initial::after { .mail-card {
padding: 0.8rem;
margin: 0 0.2rem;
border-radius: 0.5rem;
}
.contact::before,
.mail-card::before {
content: ""; content: "";
position: absolute; position: absolute;
bottom: -0.1rem; top: 0;
right: -0.1rem; margin: 0.5rem;
height: 1rem; padding: 0.3rem;
width: 1rem;
background: var(--accent-color); background: var(--accent-color);
border-radius: 100%; border-radius: 100%;
border: solid rgba(var(--foreground-color), 1) 1px; border: solid rgba(var(--foreground-color), 1) 1px;
@ -1213,8 +1242,8 @@ sm-button[variant=primary] {
transition: transform 0.3s; transition: transform 0.3s;
} }
.contact.unread .initial::after, .contact.unread::before,
.mail-card.unread .initial::after { .mail-card.unread::before {
transform: scale(1); transform: scale(1);
} }
@ -1241,12 +1270,10 @@ sm-button[variant=primary] {
position: relative; position: relative;
display: grid; display: grid;
gap: 0 1rem; gap: 0 1rem;
padding: 0.8rem 1.5rem;
align-items: center; align-items: center;
flex-shrink: 0; flex-shrink: 0;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
grid-template-columns: auto 1fr auto; grid-template-columns: auto 1fr auto;
grid-template-areas: "dp sender date" "dp subject subject" "dp desc desc"; grid-template-areas: "dp sender date" "dp subject subject" "dp desc desc";
@ -1254,8 +1281,6 @@ sm-button[variant=primary] {
.mail-card .initial { .mail-card .initial {
grid-area: dp; grid-area: dp;
align-self: flex-start; align-self: flex-start;
height: 2rem;
width: 2rem;
font-size: 1rem; font-size: 1rem;
} }
.mail-card .sender { .mail-card .sender {
@ -1380,7 +1405,7 @@ sm-button[variant=primary] {
#main_navbar { #main_navbar {
display: flex; display: flex;
background: rgba(var(--text-color), 0.03); background: rgba(var(--foreground-color), 1);
} }
#main_navbar.hide-away { #main_navbar.hide-away {
position: absolute; position: absolute;
@ -1396,23 +1421,26 @@ sm-button[variant=primary] {
.nav-item { .nav-item {
position: relative; position: relative;
display: flex; display: grid;
flex: 1;
width: 100%; width: 100%;
flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-items: center;
padding: 0.5rem 0.3rem; padding: 0.5rem 0.4rem;
color: var(--text-color); color: var(--text-color);
font-size: 0.8rem; font-size: 0.8rem;
border-radius: 0.3rem; border-radius: 0.5rem;
font-weight: 500; font-weight: 500;
aspect-ratio: 1/1;
} }
.nav-item .icon { .nav-item .icon {
grid-area: 1/1/2/2;
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
} }
.nav-item .filled {
opacity: 0;
}
.nav-item__title { .nav-item__title {
margin-top: 0.3rem; line-height: 1;
transition: opacity 0.2s, transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: opacity 0.2s, transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
} }
.nav-item--active { .nav-item--active {
@ -1422,6 +1450,12 @@ sm-button[variant=primary] {
fill: var(--accent-color); fill: var(--accent-color);
transform: translateY(50%); transform: translateY(50%);
} }
.nav-item--active .icon.filled {
opacity: 1;
}
.nav-item--active .icon:not(.filled) {
opacity: 0;
}
.nav-item--active .nav-item__title { .nav-item--active .nav-item__title {
transform: translateY(100%); transform: translateY(100%);
opacity: 0; opacity: 0;
@ -1458,6 +1492,37 @@ sm-button[variant=primary] {
margin: 0.3rem; margin: 0.3rem;
} }
#contacts,
#mails,
#settings {
height: 100%;
overflow-y: hidden;
}
#contacts .header,
#mails .header,
#settings .header {
padding: 1rem;
position: relative;
gap: 0.5rem;
min-height: 4rem;
}
#contacts .header sm-input,
#mails .header sm-input,
#settings .header sm-input {
width: 100%;
}
#contacts .header h4,
#mails .header h4,
#settings .header h4 {
text-transform: capitalize;
font-weight: 500;
}
#contacts .header sm-menu,
#mails .header sm-menu,
#settings .header sm-menu {
margin-right: -0.7rem;
}
#auto_complete_contact { #auto_complete_contact {
position: relative; position: relative;
} }
@ -1484,6 +1549,11 @@ sm-button[variant=primary] {
#contacts { #contacts {
position: relative; position: relative;
overflow-x: hidden; overflow-x: hidden;
grid-template-rows: -webkit-max-content -webkit-max-content 1fr;
grid-template-rows: max-content max-content 1fr;
}
#contacts .header {
padding: 0.5rem 1rem;
} }
#contacts .scrolling-wrapper { #contacts .scrolling-wrapper {
height: 100%; height: 100%;
@ -1499,7 +1569,7 @@ sm-button[variant=primary] {
padding: 0.5rem 0; padding: 0.5rem 0;
} }
#group_creation_process .group-icon { #creation_process .group-icon {
background-color: var(--accent-color); background-color: var(--accent-color);
justify-self: center; justify-self: center;
height: 8rem; height: 8rem;
@ -1510,7 +1580,6 @@ sm-button[variant=primary] {
font-size: 4rem; font-size: 4rem;
} }
#contacts,
#mails { #mails {
position: relative; position: relative;
grid-template-rows: -webkit-max-content 1fr; grid-template-rows: -webkit-max-content 1fr;
@ -1533,72 +1602,8 @@ sm-button[variant=primary] {
margin: 0rem; margin: 0rem;
} }
#contacts,
#mails,
#settings {
height: 100%;
overflow-y: hidden;
}
#contacts .header,
#mails .header,
#settings .header {
padding: 1rem 1.5rem;
position: relative;
gap: 0.5rem;
min-height: 4rem;
}
#contacts .header .expanding-search,
#mails .header .expanding-search,
#settings .header .expanding-search {
position: absolute;
width: 100%;
padding: 0.7rem 1.5rem;
background: rgba(var(--foreground-color), 1);
}
#contacts .header sm-input,
#mails .header sm-input,
#settings .header sm-input {
width: 100%;
}
#contacts .header h4,
#mails .header h4,
#settings .header h4 {
text-transform: capitalize;
font-weight: 500;
}
#contacts .header .flex h4,
#mails .header .flex h4,
#settings .header .flex h4 {
flex: 1;
}
#contacts .header .flex sm-menu,
#mails .header .flex sm-menu,
#settings .header .flex sm-menu {
margin-right: -0.7rem;
}
#contacts .header sm-button,
#mails .header sm-button,
#settings .header sm-button {
margin: 0;
}
#contacts .header sm-button .icon,
#mails .header sm-button .icon,
#settings .header sm-button .icon {
height: 0.9rem;
width: 0.9rem;
align-self: center;
stroke-width: 8;
margin-left: 0;
margin-right: 0.5rem;
}
#chat_search_field .icon-only {
margin-left: -0.5rem;
margin-right: 0.5rem;
}
#search_chats { #search_chats {
--min-height: 3rem; --min-height: 2.5rem;
} }
#chat_page, #chat_page,
@ -1642,7 +1647,7 @@ sm-button[variant=primary] {
max-width: max-content; max-width: max-content;
margin-bottom: 0.2rem; margin-bottom: 0.2rem;
margin-top: 0.8rem; margin-top: 0.8rem;
padding: 0.6em 1em; padding: 0.5em 0.8em;
transition: opacity 0.3s, transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: opacity 0.3s, transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
} }
.message .sender-name { .message .sender-name {
@ -1659,8 +1664,7 @@ sm-button[variant=primary] {
word-break: break-all; word-break: break-all;
word-break: break-word; word-break: break-word;
-webkit-hyphens: auto; -webkit-hyphens: auto;
-ms-hyphens: auto; hyphens: auto;
hyphens: auto;
white-space: pre-wrap; white-space: pre-wrap;
line-height: 1.5; line-height: 1.5;
} }
@ -1686,7 +1690,7 @@ sm-button[variant=primary] {
.sent { .sent {
margin-left: auto; margin-left: auto;
background: var(--accent-color); background: var(--accent-color);
border-radius: 0.8rem 0 0.8rem 0.8rem; border-radius: 0.3rem 0 0.3rem 0.3rem;
} }
.sent > * { .sent > * {
color: rgba(var(--background-color), 1); color: rgba(var(--background-color), 1);
@ -1705,8 +1709,8 @@ sm-button[variant=primary] {
.received { .received {
margin-right: auto; margin-right: auto;
background: rgba(var(--text-color), 0.1); border-radius: 0 0.3rem 0.3rem 0.3rem;
border-radius: 0 0.8rem 0.8rem 0.8rem; background-color: rgba(var(--text-color), 0.1);
} }
.received::after { .received::after {
content: ""; content: "";
@ -1732,12 +1736,12 @@ sm-button[variant=primary] {
.sent + .sent, .sent + .sent,
.received + .received { .received + .received {
border-radius: 0.8rem; border-radius: 0.3rem;
} }
.distinct-sender { .distinct-sender {
display: grid; display: grid;
border-radius: 0 0.8rem 0.8rem 0.8rem !important; border-radius: 0 0.3rem 0.3rem 0.3rem !important;
margin-top: 0.8rem !important; margin-top: 0.8rem !important;
} }
.distinct-sender::after { .distinct-sender::after {
@ -1879,7 +1883,6 @@ sm-button[variant=primary] {
#type_message { #type_message {
margin: 0; margin: 0;
--border-radius: 0.5rem;
--background: rgba(var(--text-color), 0.1); --background: rgba(var(--text-color), 0.1);
} }
@ -1900,7 +1903,6 @@ sm-button[variant=primary] {
--button-hover-background: rgba(var(--text-color), 0.2); --button-hover-background: rgba(var(--text-color), 0.2);
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
width: 100%; width: 100%;
max-height: 40vh; max-height: 40vh;
@ -1913,7 +1915,6 @@ sm-button[variant=primary] {
border-radius: 0.6rem; border-radius: 0.6rem;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
text-align: center; text-align: center;
} }
@ -1937,6 +1938,7 @@ sm-button[variant=primary] {
} }
#chats_list { #chats_list {
gap: 0.2rem;
padding-bottom: 6rem; padding-bottom: 6rem;
} }
@ -2106,7 +2108,6 @@ sm-button[variant=primary] {
sm-popup { sm-popup {
--border-radius: 1rem 1rem 0 0; --border-radius: 1rem 1rem 0 0;
} }
#landing { #landing {
grid-template-areas: "illustration" "."; grid-template-areas: "illustration" ".";
align-items: flex-start; align-items: flex-start;
@ -2120,11 +2121,9 @@ sm-button[variant=primary] {
display: flex; display: flex;
width: 100% !important; width: 100% !important;
} }
#landing_illustration { #landing_illustration {
grid-area: illustration; grid-area: illustration;
} }
.frame form, .frame form,
#sign_in form { #sign_in form {
height: 100%; height: 100%;
@ -2137,23 +2136,50 @@ sm-button[variant=primary] {
#sign_in sm-button[variant=primary] { #sign_in sm-button[variant=primary] {
margin-top: auto; margin-top: auto;
} }
.fab {
bottom: 4rem;
}
.inner-page {
margin-bottom: 5rem;
}
#main_navbar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
margin: 0.5rem auto;
border-radius: 1rem;
justify-content: center;
background-color: transparent;
-webkit-backdrop-filter: blur(0.5rem);
backdrop-filter: blur(0.5rem);
background-color: rgba(var(--foreground-color), 0.9);
}
#main_navbar ul {
background-color: rgba(var(--text-color), 0.05);
border-radius: inherit;
box-shadow: 0 1rem 1.5rem rgba(0, 0, 0, 0.16);
}
#main_navbar.hide-away { #main_navbar.hide-away {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
} }
#main_navbar .nav-item {
height: 3.8rem;
width: 4.5rem;
}
#chats_list, #chats_list,
#contact_container { #contact_container {
gap: 0.2rem; gap: 0.2rem;
} }
#chat_view .message { #chat_view .message {
width: auto; width: auto;
max-width: 90%; max-width: 90%;
} }
#chat_header { #chat_header {
grid-template-columns: auto minmax(0, 1fr); grid-template-columns: auto minmax(0, 1fr);
} }
@ -2161,7 +2187,6 @@ sm-button[variant=primary] {
max-width: calc(100% - 2rem); max-width: calc(100% - 2rem);
margin-left: -1.7rem; margin-left: -1.7rem;
} }
#settings { #settings {
overflow-x: hidden; overflow-x: hidden;
} }
@ -2176,7 +2201,6 @@ sm-button[variant=primary] {
-webkit-backdrop-filter: blur(0.5rem); -webkit-backdrop-filter: blur(0.5rem);
backdrop-filter: blur(0.5rem); backdrop-filter: blur(0.5rem);
} }
.hide-on-mobile { .hide-on-mobile {
display: none !important; display: none !important;
} }
@ -2185,38 +2209,31 @@ sm-button[variant=primary] {
.hide-on-desktop { .hide-on-desktop {
display: none !important; display: none !important;
} }
.page { .page {
padding-bottom: 0; padding-bottom: 0;
} }
.popup__header { .popup__header {
grid-column: 1/-1; grid-column: 1/-1;
padding: 1rem 1.5rem 0 1.5rem; padding: 1rem 1.5rem 0 1.5rem;
} }
.logo-section { .logo-section {
padding: 2rem 3rem 0 3rem; padding: 2rem 3rem 0 3rem;
margin: 0.5rem 0; margin: 0.5rem 0;
} }
sm-popup { sm-popup {
--width: 24rem; --width: 24rem;
--min-width: 24rem; --min-width: 24rem;
--border-radius: 0.5rem; --border-radius: 0.5rem;
} }
#landing { #landing {
align-items: center; align-items: center;
gap: 4vw; gap: 4vw;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
padding: 0 4vw; padding: 0 4vw;
} }
#sign_in { #sign_in {
width: 24rem; width: 24rem;
} }
#main_page { #main_page {
grid-template-columns: -webkit-min-content 1fr; grid-template-columns: -webkit-min-content 1fr;
grid-template-columns: min-content 1fr; grid-template-columns: min-content 1fr;
@ -2225,26 +2242,20 @@ sm-button[variant=primary] {
overflow: hidden; overflow: hidden;
box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05), 0 1rem 3rem rgba(0, 0, 0, 0.2); box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05), 0 1rem 3rem rgba(0, 0, 0, 0.2);
} }
#main_navbar { #main_navbar {
grid-area: nav; grid-area: nav;
border-top: none; border-top: none;
flex-direction: column; flex-direction: column;
background-color: rgba(var(--foreground-color), 0.3);
border-right: solid thin rgba(var(--text-color), 0.1); border-right: solid thin rgba(var(--text-color), 0.1);
background-color: rgba(var(--foreground-color), 0.3);
} }
#main_navbar ul { #main_navbar ul {
flex-direction: column; flex-direction: column;
gap: 0.5rem; gap: 0.5rem;
padding: 0.3rem;
} }
#main_navbar ul li:last-of-type { #main_navbar ul li:last-of-type {
margin-top: auto; margin-top: auto;
} }
.nav-item {
aspect-ratio: 1/1;
}
.nav-item__indicator { .nav-item__indicator {
width: 0.25rem; width: 0.25rem;
height: 50%; height: 50%;
@ -2252,26 +2263,21 @@ sm-button[variant=primary] {
border-radius: 0 1rem 1rem 0; border-radius: 0 1rem 1rem 0;
bottom: auto; bottom: auto;
} }
#add_contact_popup { #add_contact_popup {
--min-width: 24rem; --min-width: 24rem;
} }
#compose_mail_popup, #compose_mail_popup,
#reply_mail_popup { #reply_mail_popup {
--min-width: 36rem; --min-width: 36rem;
} }
#emoji_picker { #emoji_picker {
max-height: 18rem; max-height: 18rem;
} }
#chat_view .message { #chat_view .message {
width: auto; width: auto;
align-self: flex-start; align-self: flex-start;
max-width: 55ch; max-width: 55ch;
} }
#chat_page, #chat_page,
#mail_page { #mail_page {
display: grid; display: grid;
@ -2281,7 +2287,6 @@ sm-button[variant=primary] {
#mail_page > :first-child { #mail_page > :first-child {
border-right: solid thin rgba(var(--text-color), 0.1); border-right: solid thin rgba(var(--text-color), 0.1);
} }
#settings { #settings {
display: grid; display: grid;
grid-template-columns: 14rem 1fr; grid-template-columns: 14rem 1fr;
@ -2300,12 +2305,10 @@ sm-button[variant=primary] {
#settings .panel > *:first-of-type { #settings .panel > *:first-of-type {
margin-top: 0.5rem; margin-top: 0.5rem;
} }
.contact.active, .contact.active,
.mail-card.active { .mail-card.active {
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
} }
#contact_details_popup.is-group { #contact_details_popup.is-group {
--width: 52rem; --width: 52rem;
} }
@ -2329,7 +2332,6 @@ sm-button[variant=primary] {
padding: 1rem 4rem; padding: 1rem 4rem;
padding-top: 0; padding-top: 0;
} }
#chat_page, #chat_page,
#mail_page { #mail_page {
grid-template-columns: 21rem 1fr; grid-template-columns: 21rem 1fr;
@ -2343,11 +2345,9 @@ sm-button[variant=primary] {
#landing .title-font { #landing .title-font {
font-size: 3rem; font-size: 3rem;
} }
#emoji_picker { #emoji_picker {
--num-columns: 16; --num-columns: 16;
} }
.contact.active, .contact.active,
.mail-card.active { .mail-card.active {
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
@ -2358,7 +2358,6 @@ sm-button[variant=primary] {
width: 0.5rem; width: 0.5rem;
height: 0.5rem; height: 0.5rem;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background: rgba(var(--text-color), 0.3); background: rgba(var(--text-color), 0.3);
border-radius: 1rem; border-radius: 1rem;
@ -2366,21 +2365,17 @@ sm-button[variant=primary] {
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
background: rgba(var(--text-color), 0.5); background: rgba(var(--text-color), 0.5);
} }
.interactive:hover { .interactive:hover {
background-color: rgba(var(--text-color), 0.06); background-color: rgba(var(--text-color), 0.06);
} }
.emoji:hover { .emoji:hover {
cursor: pointer; cursor: pointer;
background: rgba(var(--text-color), 0.06); background: rgba(var(--text-color), 0.06);
} }
.contact .menu { .contact .menu {
opacity: 0; opacity: 0;
transition: opacity 0.3s; transition: opacity 0.3s;
} }
.contact:hover .menu { .contact:hover .menu {
opacity: 1; opacity: 1;
} }
@ -2390,7 +2385,6 @@ sm-button[variant=primary] {
.contact { .contact {
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
} }
.contact .menu { .contact .menu {
display: none; display: none;
} }
@ -2400,6 +2394,6 @@ sm-button[variant=primary] {
overflow: overlay; overflow: overlay;
} }
} }
.hide { .hidden {
display: none !important; display: none !important;
} }

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@
function onLoadStartUp() { function onLoadStartUp() {
showPage('loading') showPage('loading')
floDapps.setAppObjectStores({ userSettings: {} }) floDapps.setAppObjectStores({ userSettings: {} })
document.body.classList.remove('hide') document.body.classList.remove('hidden')
floDapps.setCustomPrivKeyInput(getSignedIn) floDapps.setCustomPrivKeyInput(getSignedIn)
getRef('emoji_picker').shadowRoot.append(style); getRef('emoji_picker').shadowRoot.append(style);
@ -61,7 +61,7 @@
<link rel="stylesheet" href="css/style.css"> <link rel="stylesheet" href="css/style.css">
</head> </head>
<body data-theme="dark" onload="onLoadStartUp()" class="hide"> <body data-theme="dark" onload="onLoadStartUp()" class="hidden">
<sm-notifications id="notification_drawer"></sm-notifications> <sm-notifications id="notification_drawer"></sm-notifications>
<sm-popup id="confirmation_popup"> <sm-popup id="confirmation_popup">
<h4 id="confirm_title"></h4> <h4 id="confirm_title"></h4>
@ -82,7 +82,7 @@
</div> </div>
</sm-form> </sm-form>
</sm-popup> </sm-popup>
<div id="secondary_pages" class="page hide"> <div id="secondary_pages" class="page hidden">
<header class="flex align-center gap-1"> <header class="flex align-center gap-1">
<div class="flex align-center flex-1"> <div class="flex align-center flex-1">
<svg class="icon flo-icon" width="64" height="64" viewBox="0 0 64 64" fill="none" <svg class="icon flo-icon" width="64" height="64" viewBox="0 0 64 64" fill="none"
@ -102,7 +102,7 @@
</div> </div>
<theme-toggle></theme-toggle> <theme-toggle></theme-toggle>
</header> </header>
<div id="landing" class="grid inner-page hide"> <div id="landing" class="grid inner-page hidden">
<div class="left"> <div class="left">
<h4> <h4>
FLO Messenger FLO Messenger
@ -122,7 +122,7 @@
<img src="assets/message-background.svg" alt=""> <img src="assets/message-background.svg" alt="">
</div> </div>
</div> </div>
<article id="sign_in" class="inner-page page-layout hide"> <article id="sign_in" class="inner-page page-layout hidden">
<section> <section>
<h1 style="font-size: 2rem;">Sign In</h1> <h1 style="font-size: 2rem;">Sign In</h1>
<p>Welcome back, glad to see you again</p> <p>Welcome back, glad to see you again</p>
@ -136,7 +136,7 @@
</p> </p>
</section> </section>
</article> </article>
<article id="sign_up" class="inner-page page-layout hide"> <article id="sign_up" class="inner-page page-layout hidden">
<section class="grid gap-1-5"> <section class="grid gap-1-5">
<div id="flo_id_warning" class="grid justify-center gap-0-5"> <div id="flo_id_warning" class="grid justify-center gap-0-5">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" <svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
@ -163,7 +163,7 @@
too. </p> too. </p>
</section> </section>
</article> </article>
<div id="loading" class="inner-page hide"> <div id="loading" class="inner-page hidden">
<svg class="page__loader" viewBox="0 0 512 512"> <svg class="page__loader" viewBox="0 0 512 512">
<defs> <defs>
<style> <style>
@ -214,47 +214,31 @@
<button class="button" onclick="floDapps.clearCredentials()">Reset</button> <button class="button" onclick="floDapps.clearCredentials()">Reset</button>
</div> </div>
</div> </div>
<main id="main_page" class="page grid hide"> <main id="main_page" class="page grid hidden">
<section id="chat_page" class="inner-page"> <section id="chat_page" class="inner-page">
<div id="contacts" class="grid"> <div id="contacts" class="grid">
<header class="grid header"> <header class="grid header">
<div class="flex align-center"> <div class="flex align-center">
<h4>FLO Messenger</h4> <sm-input id="search_chats" class="margin-right-0-5" type="search"
<button class="icon-only" onclick="toggleSearch('chat_search_field')"> placeholder="Search FLO ID or name">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" <svg slot="icon" class="icon" xmlns="http://www.w3.org/2000/svg" height="24px"
width="24px" fill="#000000"> viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" /> <path d="M0 0h24v24H0V0z" fill="none" />
<path <path
d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" /> d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" />
</svg> </svg>
</button> </sm-input>
<sm-menu align-options="right"> <sm-menu align-options="right">
<sm-menu-option onclick="openPopup('group_creation_popup')"> <sm-menu-option onclick="openCreationPopup('group')">
Create new group Create new group
</sm-menu-option> </sm-menu-option>
</sm-menu> </sm-menu>
</div> </div>
<div id="chat_search_field" class="expanding-search flex align-center hide">
<button class="icon-only" onclick="toggleSearch('chat_search_field')">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none"></path>
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"></path>
</svg>
</button>
<sm-input id="search_chats" type="search" placeholder="Search FLO ID or name"></sm-input>
</div>
</header> </header>
<button id="new_message_button" onclick="openPopup('new_message_popup')" <div class="margin-bottom-0-5" style="padding: 0 1rem;">
class="button button--primary fab round"> <button class="button button--small button--outlined" onclick="openCreationPopup('multisig')">Create
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" multisig</button>
fill="#000000"> </div>
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM5.92 19H5v-.92l9.06-9.06.92.92L5.92 19zM20.71 5.63l-2.34-2.34c-.2-.2-.45-.29-.71-.29s-.51.1-.7.29l-1.83 1.83 3.75 3.75 1.83-1.83c.39-.39.39-1.02 0-1.41z" />
</svg>
New chat
</button>
<div id="chats_list" class="flex observe-empty-state"></div> <div id="chats_list" class="flex observe-empty-state"></div>
<div class="empty-state flex flex-direction-column align-center text-center align-self-center"> <div class="empty-state flex flex-direction-column align-center text-center align-self-center">
<svg class="icon icon--big" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" <svg class="icon icon--big" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
@ -266,8 +250,18 @@
<h4 class="margin-bottom-0-5">Start your first conversation</h4> <h4 class="margin-bottom-0-5">Start your first conversation</h4>
<p>Tap/click on 'New chat' to add or select a contact.</p> <p>Tap/click on 'New chat' to add or select a contact.</p>
</div> </div>
<button id="new_message_button" onclick="openPopup('new_message_popup')"
class="button button--primary fab round">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM5.92 19H5v-.92l9.06-9.06.92.92L5.92 19zM20.71 5.63l-2.34-2.34c-.2-.2-.45-.29-.71-.29s-.51.1-.7.29l-1.83 1.83 3.75 3.75 1.83-1.83c.39-.39.39-1.02 0-1.41z" />
</svg>
New chat
</button>
</div> </div>
<div id="chat_view" class="grid hide"> <div id="chat_view" class="grid hidden">
<header id="chat_header" class="grid align-center"> <header id="chat_header" class="grid align-center">
<a class="hide-on-desktop button icon-only back-button" href="#/chat_page"> <a class="hide-on-desktop button icon-only back-button" href="#/chat_page">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" <svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
@ -297,7 +291,7 @@
</button> </button>
</div> </div>
<footer id="chat_footer" class="grid"> <footer id="chat_footer" class="grid">
<emoji-picker id="emoji_picker" class="hide"></emoji-picker> <emoji-picker id="emoji_picker" class="hidden"></emoji-picker>
<div class="flex"> <div class="flex">
<svg id="emoji_toggle" onclick="toggleEmoji('toggle')" xmlns="http://www.w3.org/2000/svg" <svg id="emoji_toggle" onclick="toggleEmoji('toggle')" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 64 64"> viewBox="0 0 64 64">
@ -310,7 +304,7 @@
</footer> </footer>
</div> </div>
</section> </section>
<section class="inner-page hide" id="mail_page"> <section class="inner-page hidden" id="mail_page">
<div id="mails" class="grid"> <div id="mails" class="grid">
<header class="grid header"> <header class="grid header">
<div class="flex align-center space-between"> <div class="flex align-center space-between">
@ -345,7 +339,7 @@
<p>Tap/click on 'New Mail' button below to compose new mail.</p> <p>Tap/click on 'New Mail' button below to compose new mail.</p>
</div> </div>
</div> </div>
<div class="hide flex h-100"> <div class="hidden flex h-100">
<ul id="sent_mail_container" class="mail-container flex observe-empty-state"></ul> <ul id="sent_mail_container" class="mail-container flex observe-empty-state"></ul>
<div class="empty-state flex flex-direction-column align-center text-center align-self-center"> <div class="empty-state flex flex-direction-column align-center text-center align-self-center">
<svg class="icon icon--big" xmlns="http://www.w3.org/2000/svg" <svg class="icon icon--big" xmlns="http://www.w3.org/2000/svg"
@ -369,7 +363,7 @@
</div> </div>
</div> </div>
</div> </div>
<div id="mail" class="flex hide-on-mobile hide"> <div id="mail" class="flex hide-on-mobile hidden">
<div id="mail_container"></div> <div id="mail_container"></div>
<div class="flex"> <div class="flex">
<sm-button id="prev_mail">View Previous Mail</sm-button> <sm-button id="prev_mail">View Previous Mail</sm-button>
@ -377,7 +371,7 @@
</div> </div>
</div> </div>
</section> </section>
<section id="settings" class="inner-page hide"> <section id="settings" class="inner-page hidden">
<aside id="settings_sidebar"> <aside id="settings_sidebar">
<header class="grid header"> <header class="grid header">
<h4>Settings</h4> <h4>Settings</h4>
@ -442,7 +436,7 @@
</button> </button>
</section> </section>
</div> </div>
<div id="chat" class="panel hide"> <div id="chat" class="panel hidden">
<sm-switch id="is_enter_send_toggle"> <sm-switch id="is_enter_send_toggle">
<div slot="left" class="flex flex-direction-column"> <div slot="left" class="flex flex-direction-column">
<h4>Send by Enter</h4> <h4>Send by Enter</h4>
@ -456,7 +450,7 @@
</div> </div>
</sm-switch> </sm-switch>
</div> </div>
<div id="blocked" class="panel hide"> <div id="blocked" class="panel hidden">
<section> <section>
<h4>Blocked</h4> <h4>Blocked</h4>
<ul id="blocked_list" class="observe-empty-state"></ul> <ul id="blocked_list" class="observe-empty-state"></ul>
@ -465,7 +459,7 @@
</div> </div>
</section> </section>
</div> </div>
<div id="personalize" class="panel hide"> <div id="personalize" class="panel hidden">
<section> <section>
<h4>Chat preview</h4> <h4>Chat preview</h4>
<div id="chat_preview"> <div id="chat_preview">
@ -489,7 +483,7 @@
<section> <section>
<h4>Set chat and mail background image</h4> <h4>Set chat and mail background image</h4>
<fieldset id="bg_preview_container" class="flex"> <fieldset id="bg_preview_container" class="flex">
<label id="selected_bg_preview" class="bg-preview hide"> <label id="selected_bg_preview" class="bg-preview hidden">
<input type="radio" name="bg" value="img"> <input type="radio" name="bg" value="img">
<img src="" alt="background preview" class="bg-preview__image"> <img src="" alt="background preview" class="bg-preview__image">
</label> </label>
@ -509,7 +503,7 @@
<input type="file" id="select_bg_image" accept="image/*" /> <input type="file" id="select_bg_image" accept="image/*" />
</label> </label>
</section> </section>
<section id="backdrop_options" class="hide"> <section id="backdrop_options" class="hidden">
<h4>App backdrop</h4> <h4>App backdrop</h4>
<label class="grid gap-0-3"> <label class="grid gap-0-3">
<span>Wallpaper dimming</span> <span>Wallpaper dimming</span>
@ -531,7 +525,7 @@
<color-grid id="accent_color_selector"></color-grid> <color-grid id="accent_color_selector"></color-grid>
</section> </section>
</div> </div>
<div id="backup" class="panel hide"> <div id="backup" class="panel hidden">
<section> <section>
<h4>Backup data</h4> <h4>Backup data</h4>
<p>Create a backup of contacts, conversations and mails. Which can later be used to restore <p>Create a backup of contacts, conversations and mails. Which can later be used to restore
@ -568,14 +562,14 @@
</label> </label>
</section> </section>
</div> </div>
<div id="about" class="panel hide"> <div id="about" class="panel hidden">
<section> <section>
<p>Created by RanchiMall, a Blockchain incorporated entity</p> <p>Created by RanchiMall, a Blockchain incorporated entity</p>
</section> </section>
</div> </div>
</div> </div>
</section> </section>
<nav id="main_navbar" class="flex hide"> <nav id="main_navbar" class="flex hidden">
<ul> <ul>
<li> <li>
<a id="chat_page_button" class="nav-item flex align-center active" href="#/chat_page" title="Chat"> <a id="chat_page_button" class="nav-item flex align-center active" href="#/chat_page" title="Chat">
@ -585,6 +579,12 @@
<path <path
d="M15 4v7H5.17l-.59.59-.58.58V4h11m1-2H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm5 4h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1z" /> d="M15 4v7H5.17l-.59.59-.58.58V4h11m1-2H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm5 4h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1z" />
</svg> </svg>
<svg class="icon filled" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000">
<path d="M0 0h24v24H0z" fill="none" />
<path
d="M21 6h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1zm-4 6V3c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z" />
</svg>
<span class="nav-item__title">Chat</span> <span class="nav-item__title">Chat</span>
</a> </a>
</li> </li>
@ -596,6 +596,12 @@
<path <path
d="M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6zm-2 0l-8 5-8-5h16zm0 12H4V8l8 5 8-5v10z" /> d="M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6zm-2 0l-8 5-8-5h16zm0 12H4V8l8 5 8-5v10z" />
</svg> </svg>
<svg class="icon filled" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000">
<path d="M0 0h24v24H0z" fill="none" />
<path
d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z" />
</svg>
<span class="nav-item__title">Mail</span> <span class="nav-item__title">Mail</span>
</a> </a>
</li> </li>
@ -607,6 +613,14 @@
<path <path
d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z" /> d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z" />
</svg> </svg>
<svg class="icon filled" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<g>
<path d="M0,0h24v24H0V0z" fill="none" />
<path
d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z" />
</g>
</svg>
<span class="nav-item__title">Settings</span> <span class="nav-item__title">Settings</span>
</a> </a>
</li> </li>
@ -649,7 +663,7 @@
<sm-form> <sm-form>
<div id="auto_complete_contact" class="flex flex-direction-column"> <div id="auto_complete_contact" class="flex flex-direction-column">
<sm-input id="send_mail_to" placeholder="To" animate required></sm-input> <sm-input id="send_mail_to" placeholder="To" animate required></sm-input>
<div id="mail_contact_list" class="hide contact-list"></div> <div id="mail_contact_list" class="hidden contact-list"></div>
</div> </div>
<sm-input id="subject_of_mail" placeholder="Subject" animate></sm-input> <sm-input id="subject_of_mail" placeholder="Subject" animate></sm-input>
<sm-textarea id="mail_content" placeholder="Type a mail" name="" id="" rows="10" required></sm-textarea> <sm-textarea id="mail_content" placeholder="Type a mail" name="" id="" rows="10" required></sm-textarea>
@ -699,22 +713,22 @@
<h5 id="flo_id_type">FLO ID</h5> <h5 id="flo_id_type">FLO ID</h5>
<sm-copy id="contact_flo_id"></sm-copy> <sm-copy id="contact_flo_id"></sm-copy>
</div> </div>
<div id="group_description_card" class="hide"> <div id="group_description_card" class="hidden">
<h5>Group description</h5> <h5>Group description</h5>
<text-field id="group_description"></text-field> <text-field id="group_description"></text-field>
</div> </div>
<fieldset id="contact_options"></fieldset> <fieldset id="contact_options"></fieldset>
</div> </div>
<div id="group_members_card" class="hide"> <div id="group_members_card" class="hidden">
<div class="flex align-center"> <div class="flex align-center">
<h4 class="h4">Group members</h4> <h4 class="h4">Group members</h4>
<button id="edit_group_button" class="button hide justify-right" <button id="edit_group_button" class="button hidden justify-right"
onclick="editGroupMembers()">Edit</button> onclick="editGroupMembers()">Edit</button>
</div> </div>
<p id="group_members_tip" class="tip">Select members to remove or add new <p id="group_members_tip" class="tip">Select members to remove or add new
members</p> members</p>
<div id="member_options" class="flex hide"> <div id="member_options" class="flex hidden">
<button id="remove_members_button" class="button button--danger hide" <button id="remove_members_button" class="button button--danger hidden"
onclick="removeGroupMembers()"> onclick="removeGroupMembers()">
Remove selected</button> Remove selected</button>
<button id="init_add_members_button" class="button" onclick="openPopup('contacts_popup')">Add <button id="init_add_members_button" class="button" onclick="openPopup('contacts_popup')">Add
@ -738,7 +752,7 @@
</header> </header>
<div class="scrolling-wrapper grid gap-1-5"> <div class="scrolling-wrapper grid gap-1-5">
<fieldset id="all_contacts_options"> <fieldset id="all_contacts_options">
<button id="create_group_option" class="option interactive" onclick="openPopup('group_creation_popup')"> <button id="create_group_option" class="option interactive" onclick="openCreationPopup('group')">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" <svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
fill="#000000"> fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" /> <path d="M0 0h24v24H0V0z" fill="none" />
@ -760,6 +774,19 @@
</svg> </svg>
Add contact Add contact
</button> </button>
<button id="crate_multisig_option" class="option interactive" onclick="openCreationPopup('multisig')">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px"
viewBox="0 0 24 24" width="24px" fill="#000000">
<g>
<rect fill="none" height="24" width="24" />
</g>
<g>
<path
d="M20,9V6h-2v3h-3v2h3v3h2v-3h3V9H20z M9,12c2.21,0,4-1.79,4-4c0-2.21-1.79-4-4-4S5,5.79,5,8C5,10.21,6.79,12,9,12z M9,6 c1.1,0,2,0.9,2,2c0,1.1-0.9,2-2,2S7,9.1,7,8C7,6.9,7.9,6,9,6z M15.39,14.56C13.71,13.7,11.53,13,9,13c-2.53,0-4.71,0.7-6.39,1.56 C1.61,15.07,1,16.1,1,17.22V20h16v-2.78C17,16.1,16.39,15.07,15.39,14.56z M15,18H3v-0.78c0-0.38,0.2-0.72,0.52-0.88 C4.71,15.73,6.63,15,9,15c2.37,0,4.29,0.73,5.48,1.34C14.8,16.5,15,16.84,15,17.22V18z" />
</g>
</svg>
Create multisig address
</button>
</fieldset> </fieldset>
<div class="grid gap-1"> <div class="grid gap-1">
<h5>Contacts</h5> <h5>Contacts</h5>
@ -772,7 +799,7 @@
</div> </div>
</div> </div>
</sm-popup> </sm-popup>
<sm-popup id="group_creation_popup"> <sm-popup id="creation_popup">
<header class="grid popup__header" slot="header"> <header class="grid popup__header" slot="header">
<div class="flex align-center"> <div class="flex align-center">
<button class="popup__header__close justify-self-start"> <button class="popup__header__close justify-self-start">
@ -783,22 +810,21 @@
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" /> d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
</svg> </svg>
</button> </button>
<h4>Create group</h4> <h4 id="creation_popup__title">Create group</h4>
</div> </div>
</header> </header>
<div id="group_creation_process"> <div id="creation_process">
<div> <div>
<div id="selected_contacts"> <div id="selected_contacts">
<div class="flex align-center space-between"> <div class="flex align-center space-between">
<h4>Select group members</h4> <h4>Select members</h4>
<button id="skip_members_button" class="button button--primary" <button id="skip_members_button" class="button button--primary hidden">
onclick="showChildElement('group_creation_process',1,{entry: slideInLeft, exit: slideOutLeft})">
Skip </button> Skip </button>
</div> </div>
<div id="selected_contacts_container" class="observe-empty-state"></div> <div id="selected_contacts_container" class="observe-empty-state"></div>
<div class="empty-state"> <div class="empty-state">
<p class="warning">*Contacts that haven't yet replied to you, can't be added to a <p class="info info--warning">*Contacts that haven't yet replied to you, won't be visible here.
group. So they won't be visible here.</p> </p>
</div> </div>
</div> </div>
<div class="scrolling-wrapper"> <div class="scrolling-wrapper">
@ -808,9 +834,9 @@
</div> </div>
</div> </div>
</div> </div>
<sm-form class="hide"> <sm-form class="hidden">
<button class="button icon-only back-button justify-self-start" <button class="button icon-only back-button justify-self-start"
onclick="showChildElement('group_creation_process',0,{entry: slideInRight, exit: slideOutRight})"> onclick="showChildElement('creation_process',0,{entry: slideInRight, exit: slideOutRight})">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" <svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
fill="#000000"> fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" /> <path d="M0 0h24v24H0V0z" fill="none" />
@ -839,6 +865,28 @@
</button> </button>
</div> </div>
</sm-form> </sm-form>
<div class="grid gap-1-5 hidden">
<button class="button icon-only back-button justify-self-start"
onclick="showChildElement('creation_process',0,{entry: slideInRight, exit: slideOutRight})">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" />
</svg>
</button>
<p id="multisig_creation__warning" class="info info--warning"></p>
<sm-form>
<p>Enter minimum signatures required for approval of a transaction</p>
<sm-input id="min_sign_required" placeholder="Min required" min="1" type="number"
error-text="At least 1 member is required" animate required>
</sm-input>
<div class="multi-state-button">
<button id="create_multisig_button" class="button button--primary" type="submit" disabled>
Create
</button>
</div>
</sm-form>
</div>
</div> </div>
</sm-popup> </sm-popup>
@ -859,7 +907,8 @@
<button id="add_members_button" class="button button--primary" disabled>Add</button> <button id="add_members_button" class="button button--primary" disabled>Add</button>
</div> </div>
</header> </header>
<p class="warning">*Contacts that haven't yet replied to you, can't be added to a group. So they won't be <p class="info info--warning">*Contacts that haven't yet replied to you, can't be added to a group. So they
won't be
visible here.</p> visible here.</p>
<div id="popup_contacts_container" class="observe-empty-state"></div> <div id="popup_contacts_container" class="observe-empty-state"></div>
<div class="empty-state"> <div class="empty-state">
@ -1077,18 +1126,18 @@
getRef("group_description").value = description === '' ? 'Add group description' : description; getRef("group_description").value = description === '' ? 'Add group description' : description;
render.groupMembers(floID) render.groupMembers(floID)
getRef('contact_details_popup').classList.add('is-group'); getRef('contact_details_popup').classList.add('is-group');
getRef('group_members_card').classList.remove('hide') getRef('group_members_card').classList.remove('hidden')
getRef('group_description_card').classList.remove('hide') getRef('group_description_card').classList.remove('hidden')
getRef('edit_group_button').dataset.groupId = floID; getRef('edit_group_button').dataset.groupId = floID;
getRef('flo_id_type').textContent = 'Group FLO ID' getRef('flo_id_type').textContent = 'Group FLO ID'
if (isAdmin) { if (isAdmin) {
getRef('contact_name').disabled = false getRef('contact_name').disabled = false
getRef('group_description').disabled = false getRef('group_description').disabled = false
getRef('edit_group_button').classList.remove('hide') getRef('edit_group_button').classList.remove('hidden')
} else { } else {
getRef('contact_name').disabled = true getRef('contact_name').disabled = true
getRef('group_description').disabled = true getRef('group_description').disabled = true
getRef('edit_group_button').classList.add('hide') getRef('edit_group_button').classList.add('hidden')
} }
} else { } else {
getRef('flo_id_type').textContent = 'FLO ID' getRef('flo_id_type').textContent = 'FLO ID'
@ -1096,8 +1145,8 @@
getRef('contact_initial').textContent = getContactName(floID).charAt(0) getRef('contact_initial').textContent = getContactName(floID).charAt(0)
getRef("last_interaction_time").textContent = ``; getRef("last_interaction_time").textContent = ``;
getRef('contact_details_popup').classList.remove('is-group'); getRef('contact_details_popup').classList.remove('is-group');
getRef('group_members_card').classList.add('hide') getRef('group_members_card').classList.add('hidden')
getRef('group_description_card').classList.add('hide') getRef('group_description_card').classList.add('hidden')
} }
getRef('contact_initial').setAttribute('style', `--contact-color: var(${contactColor(floID)})`) getRef('contact_initial').setAttribute('style', `--contact-color: var(${contactColor(floID)})`)
getRef('contact_name').value = getContactName(floID) getRef('contact_name').value = getContactName(floID)
@ -1115,9 +1164,14 @@
isRemovingMember = false isRemovingMember = false
break break
case 'new_message_popup': case 'new_message_popup':
if (Object.keys(floGlobals.contacts).length) {
getRef('search_contacts').classList.remove('hidden')
} else {
getRef('search_contacts').classList.add('hidden')
}
renderContactList(floGlobals.contacts) renderContactList(floGlobals.contacts)
break break
case 'group_creation_popup': case 'creation_popup':
const validContacts = [] const validContacts = []
for (const floID in floGlobals.contacts) { for (const floID in floGlobals.contacts) {
if (floGlobals.pubKeys.hasOwnProperty(floID)) { if (floGlobals.pubKeys.hasOwnProperty(floID)) {
@ -1150,8 +1204,8 @@
isRemovingMember = true isRemovingMember = true
membersToAdd.clear() membersToAdd.clear()
break; break;
case 'group_creation_popup': case 'creation_popup':
showChildElement('group_creation_process', 0) showChildElement('creation_process', 0)
renderElem(getRef('select_contacts_container'), html``) renderElem(getRef('select_contacts_container'), html``)
clearAllMembers() clearAllMembers()
break; break;
@ -1341,7 +1395,7 @@
} }
window.addEventListener('hashchange', e => showPage(window.location.hash)) window.addEventListener('hashchange', e => showPage(window.location.hash))
window.addEventListener("load", () => { window.addEventListener("load", () => {
document.body.classList.remove('hide') document.body.classList.remove('hidden')
document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = floCrypto.validateAddr) document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = floCrypto.validateAddr)
document.addEventListener('keyup', (e) => { document.addEventListener('keyup', (e) => {
if (e.key === 'Escape') { if (e.key === 'Escape') {
@ -1481,7 +1535,7 @@
easing: 'ease-out', easing: 'ease-out',
}) })
getRef('chat_view').classList.remove('hide') getRef('chat_view').classList.remove('hidden')
getRef('chat_view').classList.remove('hide-on-mobile') getRef('chat_view').classList.remove('hide-on-mobile')
getRef('contacts').classList.add('hide-on-mobile') getRef('contacts').classList.add('hide-on-mobile')
getRef('main_navbar').classList.add('hide-on-mobile') getRef('main_navbar').classList.add('hide-on-mobile')
@ -1512,7 +1566,7 @@
showChildElement('mail_sections', childIndex) showChildElement('mail_sections', childIndex)
getRef("mail_type_selector").value = subPageId1 getRef("mail_type_selector").value = subPageId1
if (subPageId2 && activeMail) { if (subPageId2 && activeMail) {
getRef('mail').classList.remove('hide') getRef('mail').classList.remove('hidden')
getRef('mail').classList.remove('hide-on-mobile') getRef('mail').classList.remove('hide-on-mobile')
getRef('mails').classList.add('hide-on-mobile') getRef('mails').classList.add('hide-on-mobile')
getRef('main_navbar').classList.add('hide-on-mobile') getRef('main_navbar').classList.add('hide-on-mobile')
@ -1547,8 +1601,8 @@
const currentActiveElement = document.querySelector(`.nav-item[href="#/${pageId}"]`) const currentActiveElement = document.querySelector(`.nav-item[href="#/${pageId}"]`)
if (currentActiveElement) { if (currentActiveElement) {
getRef('main_page').classList.remove('nav-hidden') getRef('main_page').classList.remove('nav-hidden')
if (getRef('main_navbar').classList.contains('hide')) { if (getRef('main_navbar').classList.contains('hidden')) {
getRef('main_navbar').classList.remove('hide-away', 'hide') getRef('main_navbar').classList.remove('hide-away', 'hidden')
getRef('main_navbar').animate([ getRef('main_navbar').animate([
{ {
transform: isMobileView ? `translateY(100%)` : `translateX(-100%)`, transform: isMobileView ? `translateY(100%)` : `translateX(-100%)`,
@ -1603,7 +1657,7 @@
currentActiveElement.classList.add('nav-item--active') currentActiveElement.classList.add('nav-item--active')
} else { } else {
getRef('main_page').classList.add('nav-hidden') getRef('main_page').classList.add('nav-hidden')
if (!getRef('main_navbar').classList.contains('hide')) { if (!getRef('main_navbar').classList.contains('hidden')) {
getRef('main_navbar').classList.add('hide-away') getRef('main_navbar').classList.add('hide-away')
getRef('main_navbar').animate([ getRef('main_navbar').animate([
{ {
@ -1619,14 +1673,14 @@
fill: 'forwards', fill: 'forwards',
easing: 'ease' easing: 'ease'
}).onfinish = () => { }).onfinish = () => {
getRef('main_navbar').classList.add('hide') getRef('main_navbar').classList.add('hidden')
} }
} }
} }
document.querySelectorAll('.page').forEach(page => page.classList.add('hide')) document.querySelectorAll('.page').forEach(page => page.classList.add('hidden'))
getRef(pageId).closest('.page').classList.remove('hide') getRef(pageId).closest('.page').classList.remove('hidden')
document.querySelectorAll('.inner-page').forEach(page => page.classList.add('hide')) document.querySelectorAll('.inner-page').forEach(page => page.classList.add('hidden'))
getRef(pageId).classList.remove('hide') getRef(pageId).classList.remove('hidden')
getRef(pageId).animate([ getRef(pageId).animate([
{ {
opacity: 0, opacity: 0,
@ -1912,24 +1966,24 @@
easing: 'ease', easing: 'ease',
fill: 'forwards' fill: 'forwards'
} }
const visibleElement = [...getRef(id).children].find(elem => !elem.classList.contains(mobileView ? 'hide-on-mobile' : 'hide')); const visibleElement = [...getRef(id).children].find(elem => !elem.classList.contains(mobileView ? 'hide-on-mobile' : 'hidden'));
if (visibleElement === getRef(id).children[index]) return; if (visibleElement === getRef(id).children[index]) return;
visibleElement.getAnimations().forEach(anim => anim.cancel()) visibleElement.getAnimations().forEach(anim => anim.cancel())
getRef(id).children[index].getAnimations().forEach(anim => anim.cancel()) getRef(id).children[index].getAnimations().forEach(anim => anim.cancel())
if (visibleElement) { if (visibleElement) {
if (exit) { if (exit) {
visibleElement.animate(exit, animOptions).onfinish = () => { visibleElement.animate(exit, animOptions).onfinish = () => {
visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hide') visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hidden')
getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hide') getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
if (entry) if (entry)
getRef(id).children[index].animate(entry, animOptions) getRef(id).children[index].animate(entry, animOptions)
} }
} else { } else {
visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hide') visibleElement.classList.add(mobileView ? 'hide-on-mobile' : 'hidden')
getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hide') getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
} }
} else { } else {
getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hide') getRef(id).children[index].classList.remove(mobileView ? 'hide-on-mobile' : 'hidden')
getRef(id).children[index].animate(entry, animOptions) getRef(id).children[index].animate(entry, animOptions)
} }
} }
@ -1975,11 +2029,8 @@
</script> </script>
<script> <script>
let activeChat = {}, let activeChat = {};
activeMail, let activeMail;
frag = document.createDocumentFragment()
let renderedDates = {} let renderedDates = {}
let lastSender = '' let lastSender = ''
@ -2194,7 +2245,7 @@
${initial} ${initial}
</div> </div>
<h4 class="name wrap-around">${name}</h4> <h4 class="name wrap-around">${name}</h4>
${isAdmin ? html`<p class="admin-tag">Group admin</p>` : ''} ${isAdmin ? html`<p class="admin-tag">Admin</p>` : ''}
</div> </div>
`) `)
@ -2405,7 +2456,7 @@
} }
} else { } else {
if (floID) { if (floID) {
if(!(floID in messenger.chats)) if (!(floID in messenger.chats))
messenger.addChat(floID) messenger.addChat(floID)
getRef('chats_list').prepend(html.node`${render.contactCard(floID, { type: 'chat', prepend: true, markUnread: true, ref: getRef('chats_list') })}`) getRef('chats_list').prepend(html.node`${render.contactCard(floID, { type: 'chat', prepend: true, markUnread: true, ref: getRef('chats_list') })}`)
} else if (groupID) { } else if (groupID) {
@ -2450,7 +2501,7 @@
getRef('search_chats').addEventListener('keyup', e => { getRef('search_chats').addEventListener('keyup', e => {
if (e.code === 'ArrowDown') { if (e.code === 'ArrowDown') {
for (child of getRef('chats_list').children) { for (child of getRef('chats_list').children) {
if (!child.classList.contains('hide')) { if (!child.classList.contains('hidden')) {
child.focus() child.focus()
break break
} }
@ -2458,7 +2509,7 @@
} }
if (e.code === 'Enter' && getRef('contacts_container').firstElementChild) { if (e.code === 'Enter' && getRef('contacts_container').firstElementChild) {
for (child of getRef('contacts_container').children) { for (child of getRef('contacts_container').children) {
if (!child.classList.contains('hide')) { if (!child.classList.contains('hidden')) {
child.click() child.click()
break break
} }
@ -2490,27 +2541,27 @@
} }
if (e.code === 'Enter' || e.code === 'Space') { if (e.code === 'Enter' || e.code === 'Space') {
getRef('send_mail_to').value = document.activeElement.dataset.floId getRef('send_mail_to').value = document.activeElement.dataset.floId
getRef('mail_contact_list').classList.add('hide') getRef('mail_contact_list').classList.add('hidden')
} }
} }
}) })
getRef('send_mail_to').addEventListener('input', function () { getRef('send_mail_to').addEventListener('input', function () {
getRef('mail_contact_list').classList.remove('hide') getRef('mail_contact_list').classList.remove('hidden')
if (this.value.trim !== '') { if (this.value.trim !== '') {
[...getRef('mail_contact_list').children].forEach(child => { [...getRef('mail_contact_list').children].forEach(child => {
if (getContactName(child.dataset.floId).includes(this.value.trim())) { if (getContactName(child.dataset.floId).includes(this.value.trim())) {
child.classList.remove('hide') child.classList.remove('hidden')
} else { } else {
child.classList.add('hide') child.classList.add('hidden')
} }
}) })
} }
}) })
getRef('compose_mail_popup').addEventListener('click', e => { getRef('compose_mail_popup').addEventListener('click', e => {
if (e.target.closest('#send_mail_to') || e.target.closest('#mail_contact_list')) { if (e.target.closest('#send_mail_to') || e.target.closest('#mail_contact_list')) {
getRef('mail_contact_list').classList.remove('hide') getRef('mail_contact_list').classList.remove('hidden')
} else { } else {
getRef('mail_contact_list').classList.add('hide') getRef('mail_contact_list').classList.add('hidden')
} }
}) })
@ -2529,9 +2580,9 @@
const contacts = getRef('chats_list').querySelectorAll('.contact') const contacts = getRef('chats_list').querySelectorAll('.contact')
contacts.forEach(child => { contacts.forEach(child => {
if (`${getContactName(child.dataset.floId)}${child.dataset.floId}`.toLowerCase().includes(this.value.toLowerCase())) { if (`${getContactName(child.dataset.floId)}${child.dataset.floId}`.toLowerCase().includes(this.value.toLowerCase())) {
child.classList.remove('hide') child.classList.remove('hidden')
} else { } else {
child.classList.add('hide') child.classList.add('hidden')
} }
}) })
}) })
@ -2594,7 +2645,7 @@
getRef('mail_contact_list').addEventListener('click', e => { getRef('mail_contact_list').addEventListener('click', e => {
if (e.target.closest('.contact-list__item')) { if (e.target.closest('.contact-list__item')) {
getRef('send_mail_to').value = e.target.closest('.contact-list__item').dataset.floId getRef('send_mail_to').value = e.target.closest('.contact-list__item').dataset.floId
getRef('mail_contact_list').classList.add('hide') getRef('mail_contact_list').classList.add('hidden')
} }
}) })
@ -2635,6 +2686,37 @@
event.preventDefault(); event.preventDefault();
} }
function openCreationPopup(type) {
let popupTitle = ''
switch (type) {
case 'group':
popupTitle = 'Create group'
getRef('skip_members_button').classList.remove('hidden')
break;
case 'multisig':
getRef('skip_members_button').classList.add('hidden')
popupTitle = 'Create multisig address'
getRef('multisig_creation__warning').classList.add('hide')
floBlockchainAPI.getBalance(floDapps.user.id).then(balance => {
let warning = `Creation of multisig address consumes FLO, you have ${balance} FLO.`;
getRef('multisig_creation__warning').classList.add('info--warning')
if (balance < 0.2) {
warning = `Creation of multisig address consumes FLO, you don't have enough FLO`;
getRef('multisig_creation__warning').classList.remove('info--warning')
getRef('multisig_creation__warning').classList.add('info--error')
}
getRef('multisig_creation__warning').textContent = warning
getRef('skip_members_button').classList.remove('hidden')
}).catch(err => notify(err, 'error'))
break;
default:
break;
}
getRef('creation_popup__title').textContent = popupTitle
getRef('creation_popup').dataset.type = type
openPopup('creation_popup')
}
getRef('selected_contacts_container').addEventListener('wheel', transformScroll); getRef('selected_contacts_container').addEventListener('wheel', transformScroll);
getRef('select_contacts_container').addEventListener('change', e => { getRef('select_contacts_container').addEventListener('change', e => {
@ -2646,17 +2728,23 @@
delegate(getRef('selected_contacts_container'), 'click', '.remove-selected', e => { delegate(getRef('selected_contacts_container'), 'click', '.remove-selected', e => {
removeSelectedContact(e.target.closest('.contact-preview').dataset.floId) removeSelectedContact(e.target.closest('.contact-preview').dataset.floId)
}) })
const selectedGroupMembers = new Set(); const selectedMembers = new Set();
function checkSelectedMembers() { function checkSelectedMembers() {
if (selectedGroupMembers.size) { if (selectedMembers.size) {
getRef('skip_members_button').textContent = 'Next' getRef('skip_members_button').textContent = 'Next'
if (getRef('creation_popup').dataset.type === 'multisig') {
getRef('skip_members_button').classList.remove('hidden')
getRef('min_sign_required').setAttribute('max', selectedMembers.size + 1)
}
} else { } else {
getRef('skip_members_button').textContent = 'Skip' getRef('skip_members_button').textContent = 'Skip'
if (getRef('creation_popup').dataset.type === 'multisig')
getRef('skip_members_button').classList.add('hidden')
} }
} }
function selectContact(floID) { function selectContact(floID) {
if (!selectedGroupMembers.has(floID)) { if (!selectedMembers.has(floID)) {
selectedGroupMembers.add(floID) selectedMembers.add(floID)
const name = getContactName(floID) const name = getContactName(floID)
const preview = html.node`<div class="contact-preview" .dataset="${{ floId: floID }}"> const preview = html.node`<div class="contact-preview" .dataset="${{ floId: floID }}">
<div class="initial flex align-center" style=${`--contact-color: var(${contactColor(floID)})`}> <div class="initial flex align-center" style=${`--contact-color: var(${contactColor(floID)})`}>
@ -2682,7 +2770,7 @@
} }
function removeSelectedContact(floID) { function removeSelectedContact(floID) {
selectedGroupMembers.delete(floID) selectedMembers.delete(floID)
const relatedContact = getRef('select_contacts_container').querySelector(`[data-flo-id="${floID}"]`) const relatedContact = getRef('select_contacts_container').querySelector(`[data-flo-id="${floID}"]`)
const relatedPreview = getRef('selected_contacts_container').querySelector(`[data-flo-id="${floID}"]`) const relatedPreview = getRef('selected_contacts_container').querySelector(`[data-flo-id="${floID}"]`)
relatedPreview.animate( relatedPreview.animate(
@ -2701,9 +2789,39 @@
function clearAllMembers() { function clearAllMembers() {
getRef('selected_contacts_container').innerHTML = '' getRef('selected_contacts_container').innerHTML = ''
selectedGroupMembers.clear() selectedMembers.clear()
checkSelectedMembers() checkSelectedMembers()
} }
getRef('skip_members_button').addEventListener('click', e => {
if (getRef('creation_popup').dataset.type === 'multisig') {
showChildElement('creation_process', 2, { entry: slideInLeft, exit: slideOutLeft })
} else {
showChildElement('creation_process', 1, { entry: slideInLeft, exit: slideOutLeft })
}
})
getRef('min_sign_required').addEventListener('input', e => {
const { rangeOverflow, rangeUnderflow } = e.target.validity;
if (rangeUnderflow)
e.target.setAttribute('error-text', 'At least 1 member is required ')
if (rangeOverflow)
e.target.setAttribute('error-text', `Maximum ${selectedMembers.size + 1} allowed`)
})
document.getElementById('create_multisig_button').addEventListener('click', () => {
selectedMembers.add(floDapps.user.id)
const selctedPubKeys = [...selectedMembers].map(id => floGlobals.pubKeys[id]);
const minRequired = parseInt(getRef('min_sign_required').value.trim());
buttonLoader('create_multisig_button', true)
messenger.multisig.createAddress(selctedPubKeys, minRequired).then(multisigAddress => {
notify('Created multisig address', 'success');
closePopup();
clearAllMembers();
}).catch(error => notify(error, 'error'))
.finally(() => {
buttonLoader('create_multisig_button', false)
})
})
document.getElementById('create_group_button').addEventListener('click', () => { document.getElementById('create_group_button').addEventListener('click', () => {
const groupName = getRef('group_name_field').value.trim() const groupName = getRef('group_name_field').value.trim()
@ -2715,8 +2833,8 @@
getRef('chats_list').children[0].click() getRef('chats_list').children[0].click()
closePopup() closePopup()
notify('Group created', 'success') notify('Group created', 'success')
if (selectedGroupMembers.size) { if (selectedMembers.size) {
messenger.addGroupMembers(groupInfo.groupID, [...selectedGroupMembers]) messenger.addGroupMembers(groupInfo.groupID, [...selectedMembers])
.then(res => { .then(res => {
clearAllMembers() clearAllMembers()
}) })
@ -2733,12 +2851,12 @@
case 'toggle': case 'toggle':
isEmojiPickerOpen = true isEmojiPickerOpen = true
getRef('emoji_toggle').classList.toggle('active') getRef('emoji_toggle').classList.toggle('active')
getRef('emoji_picker').classList.toggle('hide') getRef('emoji_picker').classList.toggle('hidden')
break; break;
case 'hide': case 'hide':
isEmojiPickerOpen = false isEmojiPickerOpen = false
getRef('emoji_toggle').classList.remove('active') getRef('emoji_toggle').classList.remove('active')
getRef('emoji_picker').classList.add('hide') getRef('emoji_picker').classList.add('hidden')
break; break;
} }
getRef('scroll_to_bottom').setAttribute('style', `bottom: calc(${window.innerHeight - getRef('chat_footer').getBoundingClientRect().top}px - .5rem)`) getRef('scroll_to_bottom').setAttribute('style', `bottom: calc(${window.innerHeight - getRef('chat_footer').getBoundingClientRect().top}px - .5rem)`)
@ -2934,15 +3052,6 @@
} }
} }
function removeElement(element) {
element.parentNode.removeChild(element);
}
function clearElement(element) {
element.innerHTML = '';
return element;
}
function addContact() { function addContact() {
let floID = getRef('add_contact_floID').value.trim(); let floID = getRef('add_contact_floID').value.trim();
let name = getRef('add_contact_name').value.trim(); let name = getRef('add_contact_name').value.trim();
@ -2972,7 +3081,7 @@
function renderContactList(contactList = {}) { function renderContactList(contactList = {}) {
const contacts = [] const contacts = []
for (floID in contactList) { for (floID in contactList) {
let isSelected = selectedGroupMembers.has(floID) let isSelected = selectedMembers.has(floID)
contacts.push(render.contactCard(floID, { type: 'contact', isSelected, ref: getRef('contacts_container') })) contacts.push(render.contactCard(floID, { type: 'contact', isSelected, ref: getRef('contacts_container') }))
} }
renderElem(getRef('contacts_container'), html`${contacts}`) renderElem(getRef('contacts_container'), html`${contacts}`)
@ -3106,16 +3215,16 @@
//add prop for previous mail (if available) //add prop for previous mail (if available)
getRef("prev_mail").dataset["value"] = prev; getRef("prev_mail").dataset["value"] = prev;
if (prev) { if (prev) {
getRef("prev_mail").classList.remove("hide") getRef("prev_mail").classList.remove("hidden")
} else { } else {
getRef("prev_mail").classList.add("hide") getRef("prev_mail").classList.add("hidden")
} }
//set values for reply mail form if new view //set values for reply mail form if new view
if (newView) { if (newView) {
getRef('reply_mail_popup').dataset["to"] = (from === myFloID ? to.join(',') : from) getRef('reply_mail_popup').dataset["to"] = (from === myFloID ? to.join(',') : from)
getRef('reply_mail_popup').dataset["prev"] = mailRef; getRef('reply_mail_popup').dataset["prev"] = mailRef;
getRef('subject_of_reply_mail').value = subject.startsWith("Re: ") ? subject : `Re: ${subject}`; getRef('subject_of_reply_mail').value = subject.startsWith("Re: ") ? subject : `Re: ${subject}`;
getRef("show_reply_popup").classList.remove("hide"); getRef("show_reply_popup").classList.remove("hidden");
} }
messenger.removeMark(mailRef, "unread"); messenger.removeMark(mailRef, "unread");
location.hash = `#/mail_page/${getRef("mail_type_selector").value}/mail` location.hash = `#/mail_page/${getRef("mail_type_selector").value}/mail`
@ -3238,8 +3347,8 @@
document.querySelectorAll('.sidebar-item').forEach(item => item.classList.remove('active')) document.querySelectorAll('.sidebar-item').forEach(item => item.classList.remove('active'))
document.querySelector(`.sidebar-item[href="#/settings/${subPageId}"]`).classList.add('active') document.querySelector(`.sidebar-item[href="#/settings/${subPageId}"]`).classList.add('active')
document.querySelectorAll('.panel').forEach(panel => panel.classList.add('hide')) document.querySelectorAll('.panel').forEach(panel => panel.classList.add('hidden'))
getRef(subPageId).classList.remove('hide') getRef(subPageId).classList.remove('hidden')
} }
function hidePanel() { function hidePanel() {
@ -3301,25 +3410,6 @@
}) })
} }
function toggleSearch(target) {
const animOptions = {
duration: 150,
easing: 'ease',
fill: 'forwards'
}
if (getRef(target).classList.contains('hide')) {
getRef(target).classList.remove('hide')
getRef(target).animate(flyInLeft, animOptions).onfinish = () => {
getRef(target).querySelector('sm-input').focusIn()
}
} else {
getRef(target).animate(flyOutLeft, animOptions).onfinish = () => {
getRef(target).classList.add('hide')
getRef(target).querySelector('sm-input').value = ''
}
}
}
function getChatCard(floID) { function getChatCard(floID) {
return getRef('chats_list').querySelector(`.chat[data-flo-id="${floID}"], .group[data-flo-id="${floID}"]`) return getRef('chats_list').querySelector(`.chat[data-flo-id="${floID}"], .group[data-flo-id="${floID}"]`)
} }
@ -3399,7 +3489,7 @@
messenger.rmChat(floGlobals.activeFloID).then(result => { messenger.rmChat(floGlobals.activeFloID).then(result => {
getChatCard(floGlobals.activeFloID).remove() getChatCard(floGlobals.activeFloID).remove()
closePopup() closePopup()
getRef('chat_view').classList.add('hide') getRef('chat_view').classList.add('hidden')
notify('Chat deleted', 'success') notify('Chat deleted', 'success')
}) })
} }
@ -3415,15 +3505,15 @@
render.groupMembers(groupID) render.groupMembers(groupID)
membersToRemove.clear() membersToRemove.clear()
getRef('edit_group_button').textContent = 'Edit'; getRef('edit_group_button').textContent = 'Edit';
addClass(['#group_members_tip', '#member_options'], 'hide') addClass(['#group_members_tip', '#member_options'], 'hidden')
isGroupEditable = false isGroupEditable = false
isRemovingMember = false isRemovingMember = false
} else { } else {
// to-do: make group members selectable except for admin // to-do: make group members selectable except for admin
render.groupMembers(groupID, true) render.groupMembers(groupID, true)
getRef('edit_group_button').textContent = 'Done' getRef('edit_group_button').textContent = 'Done'
removeClass(['#group_members_tip', '#member_options', '#init_add_members_button'], 'hide') removeClass(['#group_members_tip', '#member_options', '#init_add_members_button'], 'hidden')
getRef('remove_members_button').classList.add('hide') getRef('remove_members_button').classList.add('hidden')
isGroupEditable = true isGroupEditable = true
isRemovingMember = true isRemovingMember = true
} }
@ -3441,11 +3531,11 @@
membersToRemove.add(floID) membersToRemove.add(floID)
} }
if (membersToRemove.size) { if (membersToRemove.size) {
addClass(['#group_members_tip', '#init_add_members_button'], 'hide') addClass(['#group_members_tip', '#init_add_members_button'], 'hidden')
getRef('remove_members_button').classList.remove('hide') getRef('remove_members_button').classList.remove('hidden')
} else { } else {
removeClass(['#group_members_tip', '#init_add_members_button'], 'hide') removeClass(['#group_members_tip', '#init_add_members_button'], 'hidden')
getRef('remove_members_button').classList.add('hide') getRef('remove_members_button').classList.add('hidden')
} }
} }
document.getElementById('popup_contacts_container').addEventListener('change', e => { document.getElementById('popup_contacts_container').addEventListener('change', e => {
@ -3529,11 +3619,11 @@
getRef('select_bg_button').textContent = 'Change background' getRef('select_bg_button').textContent = 'Change background'
getRef('selected_bg_preview').classList.add('bg-preview--selected') getRef('selected_bg_preview').classList.add('bg-preview--selected')
getRef('default_bg_preview').classList.remove('bg-preview--selected') getRef('default_bg_preview').classList.remove('bg-preview--selected')
getRef('backdrop_options').classList.remove('hide') getRef('backdrop_options').classList.remove('hidden')
} else { } else {
getRef('backdrop_options').classList.add('hide') getRef('backdrop_options').classList.add('hidden')
} }
getRef('selected_bg_preview').classList.remove('hide') getRef('selected_bg_preview').classList.remove('hidden')
getRef('selected_bg_preview').querySelector('img').src = url getRef('selected_bg_preview').querySelector('img').src = url
} }
const [bgOpacity, bgBlur] = await Promise.all([compactIDB.readData('userSettings', 'bgOpacity'), compactIDB.readData('userSettings', 'bgBlur')]) const [bgOpacity, bgBlur] = await Promise.all([compactIDB.readData('userSettings', 'bgOpacity'), compactIDB.readData('userSettings', 'bgBlur')])
@ -3560,7 +3650,7 @@
.then(async res => { .then(async res => {
getRef('background_image').src = '' getRef('background_image').src = ''
removeClass(['#chat_view', '#mail', '#chat_preview'], 'has-bg-image') removeClass(['#chat_view', '#mail', '#chat_preview'], 'has-bg-image')
getRef('backdrop_options').classList.add('hide') getRef('backdrop_options').classList.add('hidden')
}) })
.catch(err => console.error(err)) .catch(err => console.error(err))
} }

View File

@ -143,208 +143,208 @@ customElements.define('sm-button',
//Input //Input
const smInput = document.createElement('template') const smInput = document.createElement('template')
smInput.innerHTML = ` smInput.innerHTML = `
<style> <style>
*{ *{
padding: 0; padding: 0;
margin: 0; margin: 0;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
} }
input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button, input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; } input[type="search"]::-webkit-search-results-decoration { display: none; }
input[type=number] { input[type=number] {
-moz-appearance:textfield; -moz-appearance:textfield;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin: 0;
}
input::-ms-reveal,
input::-ms-clear {
display: none;
}
input:invalid{
outline: none;
-webkit-box-shadow: none;
box-shadow: none;
}
::-moz-focus-inner{
border: none;
}
:host{
display: flex;
--success-color: #00C853;
--danger-color: red;
--width: 100%;
--icon-gap: 0.5rem;
--min-height: 3.5rem;
--background: rgba(var(--text-color, (17,17,17)), 0.06);
}
.hide{
display: none !important;
}
button{
display: flex;
border: none;
background: none;
padding: 0;
border-radius: 1rem;
min-width: 0;
cursor: pointer;
}
button:focus{
outline: var(--accent-color, teal) solid medium;
}
.icon {
height: 1.2rem;
width: 1.2rem;
fill: rgba(var(--text-color, (17,17,17)), 0.6);
}
:host(.round) .input{
border-radius: 10rem;
}
.input {
display: flex;
cursor: text;
min-width: 0;
text-align: left;
align-items: center;
position: relative;
gap: var(--icon-gap);
padding: var(--padding, 0.6rem 0.8rem);
border-radius: var(--border-radius,0.3rem);
transition: opacity 0.3s, box-shadow 0.2s;
background: var(--background);
width: 100%;
outline: none;
min-height: var(--min-height);
}
.input.readonly .clear{
opacity: 0 !important;
margin-right: -2rem;
pointer-events: none !important;
}
.readonly{
pointer-events: none;
}
.input:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset !important;
}
.disabled{
pointer-events: none;
opacity: 0.6;
}
.label {
grid-area: 1/1/2/2;
font-size: inherit;
opacity: .7;
font-weight: 400;
transition: -webkit-transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s, color .03;
transform-origin: left;
pointer-events: none;
white-space: nowrap;
overflow: hidden;
width: 100%;
user-select: none;
will-change: transform;
}
.outer-container{
position: relative;
width: var(--width);
}
.container{
width: 100%;
display: grid;
grid-template-columns: 1fr auto;
position: relative;
align-items: center;
}
input{
grid-area: 1/1/2/2;
font-size: inherit;
border: none;
background: transparent;
outline: none;
color: inherit;
font-family: inherit;
width: 100%;
caret-color: var(--accent-color, teal);
}
:host([animate]) .input:focus-within .container input,
.animate-placeholder .container input {
-webkit-transform: translateY(0.6rem);
-ms-transform: translateY(0.6rem);
transform: translateY(0.6rem);
} }
input[type=number]::-webkit-inner-spin-button,
:host([animate]) .input:focus-within .label, input[type=number]::-webkit-outer-spin-button {
.animate-placeholder .label { -webkit-appearance: none;
-webkit-transform: translateY(-0.7em) scale(0.8); -moz-appearance: none;
-ms-transform: translateY(-0.7em) scale(0.8); appearance: none;
transform: translateY(-0.7em) scale(0.8); margin: 0;
opacity: 1;
color: var(--accent-color,teal)
}
:host([variant="outlined"]) .input {
box-shadow: 0 0 0 1px var(--border-color, rgba(var(--text-color, (17,17,17)), 0.3)) inset;
background: rgba(var(--background-color, (255,255,255)), 1);
}
.animate-placeholder:focus-within:not(.readonly) .label{
color: var(--accent-color,teal)
}
.feedback-text:not(:empty){
display: flex;
width: 100%;
text-align: left;
font-size: 0.9rem;
align-items: center;
padding: 0.8rem 0;
color: rgba(var(--text-color, (17,17,17)), 0.8);
}
.success{
color: var(--success-color);
}
.error{
color: var(--danger-color);
}
.status-icon{
margin-right: 0.2rem;
}
.status-icon--error{
fill: var(--danger-color);
}
.status-icon--success{
fill: var(--success-color);
}
@media (any-hover: hover){
.icon:hover{
background: rgba(var(--text-color, (17,17,17)), 0.1);
} }
} input::-ms-reveal,
</style> input::-ms-clear {
<div class="outer-container"> display: none;
<label part="input" class="input"> }
<slot name="icon"></slot> input:invalid{
<div class="container"> outline: none;
<input type="text"/> -webkit-box-shadow: none;
<div part="placeholder" class="label"></div> box-shadow: none;
<button class="clear hide" title="Clear" tabindex="-1"> }
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-11.414L9.172 7.757 7.757 9.172 10.586 12l-2.829 2.828 1.415 1.415L12 13.414l2.828 2.829 1.415-1.415L13.414 12l2.829-2.828-1.415-1.415L12 10.586z"/></svg> ::-moz-focus-inner{
</button> border: none;
</div> }
<slot name="right"></slot> :host{
</label> display: flex;
<p class="feedback-text"></p> --success-color: #00C853;
</div> --danger-color: red;
`; --width: 100%;
--icon-gap: 0.5rem;
--min-height: 3.2rem;
--background: rgba(var(--text-color, (17,17,17)), 0.06);
}
.hide{
display: none !important;
}
button{
display: flex;
border: none;
background: none;
padding: 0;
border-radius: 1rem;
min-width: 0;
cursor: pointer;
}
button:focus{
outline: var(--accent-color, teal) solid medium;
}
.icon {
height: 1.2rem;
width: 1.2rem;
fill: rgba(var(--text-color, (17,17,17)), 0.6);
}
:host(.round) .input{
border-radius: 10rem;
}
.input {
display: flex;
cursor: text;
min-width: 0;
text-align: left;
align-items: center;
position: relative;
gap: var(--icon-gap);
padding: var(--padding, 0.6rem 0.8rem);
border-radius: var(--border-radius,0.3rem);
transition: opacity 0.3s, box-shadow 0.2s;
background: var(--background);
width: 100%;
outline: none;
min-height: var(--min-height);
}
.input.readonly .clear{
opacity: 0 !important;
margin-right: -2rem;
pointer-events: none !important;
}
.readonly{
pointer-events: none;
}
.input:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset !important;
}
.disabled{
pointer-events: none;
opacity: 0.6;
}
.label {
grid-area: 1/1/2/2;
font-size: inherit;
opacity: .7;
font-weight: 400;
transition: -webkit-transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s, color .03;
transform-origin: left;
pointer-events: none;
white-space: nowrap;
overflow: hidden;
width: 100%;
user-select: none;
will-change: transform;
}
.outer-container{
position: relative;
width: var(--width);
}
.container{
width: 100%;
display: grid;
grid-template-columns: 1fr auto;
position: relative;
align-items: center;
}
input{
grid-area: 1/1/2/2;
font-size: inherit;
border: none;
background: transparent;
outline: none;
color: inherit;
font-family: inherit;
width: 100%;
caret-color: var(--accent-color, teal);
}
:host([animate]) .input:focus-within .container input,
.animate-placeholder .container input {
-webkit-transform: translateY(0.6rem);
-ms-transform: translateY(0.6rem);
transform: translateY(0.6rem);
}
:host([animate]) .input:focus-within .label,
.animate-placeholder .label {
-webkit-transform: translateY(-0.7em) scale(0.8);
-ms-transform: translateY(-0.7em) scale(0.8);
transform: translateY(-0.7em) scale(0.8);
opacity: 1;
color: var(--accent-color,teal)
}
:host([variant="outlined"]) .input {
box-shadow: 0 0 0 1px var(--border-color, rgba(var(--text-color, (17,17,17)), 0.3)) inset;
background: rgba(var(--background-color, (255,255,255)), 1);
}
.animate-placeholder:focus-within:not(.readonly) .label{
color: var(--accent-color,teal)
}
.feedback-text:not(:empty){
display: flex;
width: 100%;
text-align: left;
font-size: 0.9rem;
align-items: center;
padding: 0.8rem 0;
color: rgba(var(--text-color, (17,17,17)), 0.8);
}
.success{
color: var(--success-color);
}
.error{
color: var(--danger-color);
}
.status-icon{
margin-right: 0.2rem;
}
.status-icon--error{
fill: var(--danger-color);
}
.status-icon--success{
fill: var(--success-color);
}
@media (any-hover: hover){
.icon:hover{
background: rgba(var(--text-color, (17,17,17)), 0.1);
}
}
</style>
<div class="outer-container">
<label part="input" class="input">
<slot name="icon"></slot>
<div class="container">
<input type="text"/>
<div part="placeholder" class="label"></div>
<button class="clear hide" title="Clear" tabindex="-1">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-11.414L9.172 7.757 7.757 9.172 10.586 12l-2.829 2.828 1.415 1.415L12 13.414l2.828 2.829 1.415-1.415L13.414 12l2.829-2.828-1.415-1.415L12 10.586z"/></svg>
</button>
</div>
<slot name="right"></slot>
</label>
<p class="feedback-text"></p>
</div>
`;
customElements.define('sm-input', customElements.define('sm-input',
class extends HTMLElement { class extends HTMLElement {
@ -372,6 +372,7 @@ customElements.define('sm-input',
this.focusOut = this.focusOut.bind(this); this.focusOut = this.focusOut.bind(this);
this.fireEvent = this.fireEvent.bind(this); this.fireEvent = this.fireEvent.bind(this);
this.checkInput = this.checkInput.bind(this); this.checkInput = this.checkInput.bind(this);
this.handleKeydown = this.handleKeydown.bind(this);
this.vibrate = this.vibrate.bind(this); this.vibrate = this.vibrate.bind(this);
} }
@ -384,9 +385,9 @@ customElements.define('sm-input',
} }
set value(val) { set value(val) {
if (val === this.input.value) return;
this.input.value = val; this.input.value = val;
this.checkInput(); this.checkInput();
this.fireEvent();
} }
get placeholder() { get placeholder() {
@ -453,9 +454,9 @@ customElements.define('sm-input',
this.feedbackText.classList.add('error'); this.feedbackText.classList.add('error');
this.feedbackText.classList.remove('success'); this.feedbackText.classList.remove('success');
this.feedbackText.innerHTML = ` this.feedbackText.innerHTML = `
<svg class="status-icon status-icon--error" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg> <svg class="status-icon status-icon--error" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg>
${this._errorText} ${this._errorText}
`; `;
} }
} }
return (_isValid && _customValid); return (_isValid && _customValid);
@ -508,6 +509,15 @@ customElements.define('sm-input',
this.feedbackText.textContent = ''; this.feedbackText.textContent = '';
} }
} }
handleKeydown(e) {
if (e.key.length === 1) {
if (!['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.'].includes(e.key)) {
e.preventDefault();
} else if (e.key === '.' && e.target.value.includes('.')) {
e.preventDefault();
}
}
}
vibrate() { vibrate() {
this.outerContainer.animate([ this.outerContainer.animate([
{ transform: 'translateX(-1rem)' }, { transform: 'translateX(-1rem)' },
@ -549,6 +559,10 @@ customElements.define('sm-input',
else if (name === 'type') { else if (name === 'type') {
if (this.hasAttribute('type') && this.getAttribute('type') === 'number') { if (this.hasAttribute('type') && this.getAttribute('type') === 'number') {
this.input.setAttribute('inputmode', 'decimal'); this.input.setAttribute('inputmode', 'decimal');
this.input.addEventListener('keydown', this.handleKeydown);
} else {
this.input.removeEventListener('keydown', this.handleKeydown);
} }
} }
else if (name === 'helper-text') { else if (name === 'helper-text') {
@ -586,117 +600,118 @@ customElements.define('sm-input',
disconnectedCallback() { disconnectedCallback() {
this.input.removeEventListener('input', this.checkInput); this.input.removeEventListener('input', this.checkInput);
this.clearBtn.removeEventListener('click', this.clear); this.clearBtn.removeEventListener('click', this.clear);
this.input.removeEventListener('keydown', this.handleKeydown);
} }
}) })
//textarea
const smTextarea = document.createElement('template') const smTextarea = document.createElement('template')
smTextarea.innerHTML = ` smTextarea.innerHTML = `
<style> <style>
*, *,
*::before, *::before,
*::after { *::after {
padding: 0; padding: 0;
margin: 0; margin: 0;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
} }
::-moz-focus-inner{ ::-moz-focus-inner{
border: none; border: none;
}
.hide{
opacity: 0 !important;
}
:host{
display: grid;
--danger-color: red;
--background: rgba(var(--text-color,(17,17,17)), 0.06);
--padding: initial;
--max-height: 8rem;
}
:host([variant="outlined"]) .textarea {
box-shadow: 0 0 0 0.1rem rgba(var(--text-color,(17,17,17)), 0.4) inset;
background: rgba(var(--background-color,(255,255,255)), 1);
}
.textarea{
display: grid;
position: relative;
cursor: text;
min-width: 0;
text-align: left;
overflow: hidden auto;
grid-template-columns: 1fr;
align-items: stretch;
max-height: var(--max-height);
background: var(--background);
border-radius: var(--border-radius, 0.3rem);
padding: var(--padding);
}
.textarea::after,
textarea{
padding: 0.7rem 1rem;
width: 100%;
min-width: 1em;
font: inherit;
color: inherit;
resize: none;
grid-area: 2/1;
justify-self: stretch;
background: none;
appearance: none;
border: none;
outline: none;
line-height: 1.5;
}
.textarea::after{
content: attr(data-value) ' ';
visibility: hidden;
white-space: pre-wrap;
overflow-wrap: break-word;
word-wrap: break-word;
hyphens: auto;
overflow: hidden;
}
.readonly{
pointer-events: none;
}
.textarea:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset;
}
.placeholder{
position: absolute;
margin: 0.7rem 1rem;
opacity: .7;
font-weight: inherit;
font-size: inherit;
line-height: 1.5;
pointer-events: none;
user-select: none;
}
:host([disabled]) .textarea{
cursor: not-allowed;
opacity: 0.6;
}
@media (any-hover: hover){
::-webkit-scrollbar{
width: 0.5rem;
height: 0.5rem;
} }
.hide{
::-webkit-scrollbar-thumb{ opacity: 0 !important;
background: rgba(var(--text-color,(17,17,17)), 0.3); }
border-radius: 1rem; :host{
&:hover{ display: grid;
background: rgba(var(--text-color,(17,17,17)), 0.5); --danger-color: red;
--border-radius: 0.3rem;
--background: rgba(var(--text-color,(17,17,17)), 0.06);
--padding: initial;
--max-height: 8rem;
}
:host([variant="outlined"]) .textarea {
box-shadow: 0 0 0 0.1rem rgba(var(--text-color,(17,17,17)), 0.4) inset;
background: rgba(var(--background-color,(255,255,255)), 1);
}
.textarea{
display: grid;
position: relative;
cursor: text;
min-width: 0;
text-align: left;
overflow: hidden auto;
grid-template-columns: 1fr;
align-items: stretch;
max-height: var(--max-height);
background: var(--background);
border-radius: var(--border-radius);
padding: var(--padding);
}
.textarea::after,
textarea{
padding: 0.7rem 1rem;
width: 100%;
min-width: 1em;
font: inherit;
color: inherit;
resize: none;
grid-area: 2/1;
justify-self: stretch;
background: none;
appearance: none;
border: none;
outline: none;
line-height: 1.5;
overflow: hidden;
}
.textarea::after{
content: attr(data-value) ' ';
visibility: hidden;
white-space: pre-wrap;
overflow-wrap: break-word;
word-wrap: break-word;
hyphens: auto;
}
.readonly{
pointer-events: none;
}
.textarea:focus-within:not(.readonly){
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset;
}
.placeholder{
position: absolute;
margin: 0.7rem 1rem;
opacity: .7;
font-weight: inherit;
font-size: inherit;
line-height: 1.5;
pointer-events: none;
user-select: none;
}
:host([disabled]) .textarea{
cursor: not-allowed;
opacity: 0.6;
}
@media (any-hover: hover){
::-webkit-scrollbar{
width: 0.5rem;
height: 0.5rem;
}
::-webkit-scrollbar-thumb{
background: rgba(var(--text-color,(17,17,17)), 0.3);
border-radius: 1rem;
&:hover{
background: rgba(var(--text-color,(17,17,17)), 0.5);
}
} }
} }
} </style>
</style> <label class="textarea" part="textarea">
<label class="textarea" part="textarea"> <span class="placeholder"></span>
<span class="placeholder"></span> <textarea rows="1"></textarea>
<textarea rows="1"></textarea> </label>
</label> `;
`;
customElements.define('sm-textarea', customElements.define('sm-textarea',
class extends HTMLElement { class extends HTMLElement {
constructor() { constructor() {
@ -788,26 +803,26 @@ customElements.define('sm-textarea',
}) })
const smForm = document.createElement('template'); const smForm = document.createElement('template');
smForm.innerHTML = ` smForm.innerHTML = `
<style> <style>
*{ *{
padding: 0; padding: 0;
margin: 0; margin: 0;
box-sizing: border-box; box-sizing: border-box;
} }
:host{ :host{
display: flex; display: grid;
width: 100%; width: 100%;
} }
form{ form{
display: grid; display: inherit;
gap: var(--gap, 1.5rem); gap: var(--gap, 1.5rem);
width: 100%; width: 100%;
} }
</style> </style>
<form part="form" onsubmit="return false"> <form part="form" onsubmit="return false">
<slot></slot> <slot></slot>
</form> </form>
`; `;
customElements.define('sm-form', class extends HTMLElement { customElements.define('sm-form', class extends HTMLElement {
constructor() { constructor() {
@ -821,7 +836,7 @@ customElements.define('sm-form', class extends HTMLElement {
this.requiredElements this.requiredElements
this.submitButton this.submitButton
this.resetButton this.resetButton
this.allRequiredValid = false; this.invalidFields = false;
this.debounce = this.debounce.bind(this) this.debounce = this.debounce.bind(this)
this._checkValidity = this._checkValidity.bind(this) this._checkValidity = this._checkValidity.bind(this)
@ -839,18 +854,13 @@ customElements.define('sm-form', class extends HTMLElement {
}; };
} }
_checkValidity() { _checkValidity() {
this.allRequiredValid = this.requiredElements.every(elem => elem.isValid)
if (!this.submitButton) return; if (!this.submitButton) return;
if (this.allRequiredValid) { this.invalidFields = this.requiredElements.filter(elem => !elem.isValid)
this.submitButton.disabled = false; this.submitButton.disabled = this.invalidFields.length;
}
else {
this.submitButton.disabled = true;
}
} }
handleKeydown(e) { handleKeydown(e) {
if (e.key === 'Enter' && !e.target.tagName.includes('TEXTAREA')) { if (e.key === 'Enter' && e.target.tagName.includes('SM-INPUT')) {
if (this.allRequiredValid) { if (!this.invalidFields.length) {
if (this.submitButton) { if (this.submitButton) {
this.submitButton.click() this.submitButton.click()
} }
@ -858,9 +868,8 @@ customElements.define('sm-form', class extends HTMLElement {
bubbles: true, bubbles: true,
composed: true, composed: true,
})) }))
} } else {
else { this.requiredElements.forEach(elem => { if (!elem.isValid) elem.vibrate() })
this.requiredElements.find(elem => !elem.isValid).vibrate()
} }
} }
} }
@ -878,14 +887,22 @@ customElements.define('sm-form', class extends HTMLElement {
this._checkValidity() this._checkValidity()
} }
connectedCallback() { connectedCallback() {
const slot = this.shadowRoot.querySelector('slot') this.shadowRoot.querySelector('slot').addEventListener('slotchange', this.elementsChanged)
slot.addEventListener('slotchange', this.elementsChanged)
this.addEventListener('input', this.debounce(this._checkValidity, 100)); this.addEventListener('input', this.debounce(this._checkValidity, 100));
this.addEventListener('keydown', this.debounce(this.handleKeydown, 100)); this.addEventListener('keydown', this.debounce(this.handleKeydown, 100));
const mutationObserver = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
this.elementsChanged()
}
})
})
mutationObserver.observe(this, { childList: true, subtree: true })
} }
disconnectedCallback() { disconnectedCallback() {
this.removeEventListener('input', this.debounce(this._checkValidity, 100)); this.removeEventListener('input', this.debounce(this._checkValidity, 100));
this.removeEventListener('keydown', this.debounce(this.handleKeydown, 100)); this.removeEventListener('keydown', this.debounce(this.handleKeydown, 100));
mutationObserver.disconnect()
} }
}) })
//switch //switch
@ -1134,7 +1151,7 @@ smSelect.innerHTML = `
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;
display: flex; display: flex;
--min-width: 100%; --min-width: max-content;
} }
:host([disabled]) .select{ :host([disabled]) .select{
opacity: 0.6; opacity: 0.6;
@ -1175,7 +1192,7 @@ smSelect.innerHTML = `
grid-template-columns: 1fr auto; grid-template-columns: 1fr auto;
grid-template-areas: 'heading heading' '. .'; grid-template-areas: 'heading heading' '. .';
padding: var(--padding,0.6rem 0.8rem); padding: var(--padding,0.6rem 0.8rem);
background: rgba(var(--text-color,(17,17,17)), 0.06); background: var(--background, rgba(var(--text-color,(17,17,17)), 0.06));
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
align-items: center; align-items: center;
@ -1215,7 +1232,7 @@ smSelect.innerHTML = `
-webkit-box-shadow: 0.4rem 0.8rem 1.2rem #00000030; -webkit-box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
box-shadow: 0.4rem 0.8rem 1.2rem #00000030; box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
} }
.rotate{ :host([open]) .toggle-icon{
-webkit-transform: rotate(180deg); -webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg); -ms-transform: rotate(180deg);
transform: rotate(180deg) transform: rotate(180deg)
@ -1241,7 +1258,7 @@ smSelect.innerHTML = `
<div class="select"> <div class="select">
<div class="selection"> <div class="selection">
<div class="selected-option-text"></div> <div class="selected-option-text"></div>
<svg class="icon toggle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z"/></svg> <svg class="icon toggle-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z"/></svg>
</div> </div>
<div part="options" class="options hide"> <div part="options" class="options hide">
<slot></slot> <slot></slot>
@ -1263,9 +1280,11 @@ customElements.define('sm-select', class extends HTMLElement {
this.handleOptionSelection = this.handleOptionSelection.bind(this) this.handleOptionSelection = this.handleOptionSelection.bind(this)
this.handleKeydown = this.handleKeydown.bind(this) this.handleKeydown = this.handleKeydown.bind(this)
this.handleClickOutside = this.handleClickOutside.bind(this) this.handleClickOutside = this.handleClickOutside.bind(this)
this.selectOption = this.selectOption.bind(this)
this.availableOptions this.availableOptions
this.previousOption this.previousOption
this._value = undefined;
this.isOpen = false; this.isOpen = false;
this.label = '' this.label = ''
this.slideDown = [{ this.slideDown = [{
@ -1293,7 +1312,6 @@ customElements.define('sm-select', class extends HTMLElement {
} }
this.optionList = this.shadowRoot.querySelector('.options') this.optionList = this.shadowRoot.querySelector('.options')
this.chevron = this.shadowRoot.querySelector('.toggle')
this.selection = this.shadowRoot.querySelector('.selection') this.selection = this.shadowRoot.querySelector('.selection')
this.selectedOptionText = this.shadowRoot.querySelector('.selected-option-text') this.selectedOptionText = this.shadowRoot.querySelector('.selected-option-text')
} }
@ -1307,12 +1325,7 @@ customElements.define('sm-select', class extends HTMLElement {
const selectedOption = this.availableOptions.find(option => option.getAttribute('value') === val) const selectedOption = this.availableOptions.find(option => option.getAttribute('value') === val)
if (selectedOption) { if (selectedOption) {
this.setAttribute('value', val) this.setAttribute('value', val)
this.selectedOptionText.textContent = `${this.label}${selectedOption.textContent}`; this.selectOption(selectedOption)
if (this.previousOption) {
this.previousOption.classList.remove('check-selected')
}
selectedOption.classList.add('check-selected')
this.previousOption = selectedOption
} else { } else {
console.warn(`There is no option with ${val} as value`) console.warn(`There is no option with ${val} as value`)
} }
@ -1320,19 +1333,25 @@ customElements.define('sm-select', class extends HTMLElement {
reset(fire = true) { reset(fire = true) {
if (this.availableOptions[0] && this.previousOption !== this.availableOptions[0]) { if (this.availableOptions[0] && this.previousOption !== this.availableOptions[0]) {
const firstElement = this.availableOptions[0]; const selectedOption = this.availableOptions.find(option => option.hasAttribute('selected')) || this.availableOptions[0];
if (this.previousOption) { this.value = selectedOption.getAttribute('value')
this.previousOption.classList.remove('check-selected')
}
firstElement.classList.add('check-selected')
this.value = firstElement.getAttribute('value')
this.selectedOptionText.textContent = `${this.label}${firstElement.textContent}`
this.previousOption = firstElement;
if (fire) { if (fire) {
this.fireEvent() this.fireEvent()
} }
} }
} }
selectOption(selectedOption) {
if (this.previousOption) {
this.previousOption.classList.remove('check-selected')
this.previousOption.removeAttribute('selected')
}
if (this.previousOption !== selectedOption) {
selectedOption.classList.add('check-selected')
selectedOption.setAttribute('selected', '')
this.selectedOptionText.textContent = `${this.label}${selectedOption.textContent}`;
this.previousOption = selectedOption
}
}
focusIn() { focusIn() {
this.selection.focus() this.selection.focus()
@ -1341,11 +1360,11 @@ customElements.define('sm-select', class extends HTMLElement {
open() { open() {
this.optionList.classList.remove('hide') this.optionList.classList.remove('hide')
this.optionList.animate(this.slideDown, this.animationOptions) this.optionList.animate(this.slideDown, this.animationOptions)
this.chevron.classList.add('rotate') this.setAttribute('open', '')
this.isOpen = true this.isOpen = true
} }
collapse() { collapse() {
this.chevron.classList.remove('rotate') this.removeAttribute('open')
this.optionList.animate(this.slideUp, this.animationOptions) this.optionList.animate(this.slideUp, this.animationOptions)
.onfinish = () => { .onfinish = () => {
this.optionList.classList.add('hide') this.optionList.classList.add('hide')
@ -1437,6 +1456,11 @@ customElements.define('sm-select', class extends HTMLElement {
let slot = this.shadowRoot.querySelector('slot') let slot = this.shadowRoot.querySelector('slot')
slot.addEventListener('slotchange', e => { slot.addEventListener('slotchange', e => {
this.availableOptions = slot.assignedElements() this.availableOptions = slot.assignedElements()
this.availableOptions.forEach(elem => {
if (elem.hasAttribute('selected')) {
this._value = elem.value;
}
});
this.reset(false) this.reset(false)
}); });
this.addEventListener('click', this.handleClick) this.addEventListener('click', this.handleClick)